diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml new file mode 100644 index 0000000..e2d2cab --- /dev/null +++ b/.github/workflows/android.yml @@ -0,0 +1,48 @@ +name: Android CI + +on: + push: + branches: [ master ] + paths: + - '**/WorkflowsTrigger.kt' + +env: + TZ: Asia/Shanghai + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: set up jdk 17 + uses: actions/setup-java@v3 + with: + java-version: "17" + distribution: "oracle" + cache: gradle + + - name: grant execute permission for gradlew + run: chmod +x gradlew + + - name: build apk with gradle + run: ./gradlew app:assembleRelease + + - name: get current time + id: currentTime + run: echo "time=$(date +'%Y.%m.%d')" >> $GITHUB_OUTPUT + + - name: create a release + uses: ncipollo/release-action@v1 + with: + artifacts: "app/build/outputs/apk/release/*.apk" + body: "create by workflows" + allowUpdates: true + artifactErrorsFailBuild: true + generateReleaseNotes: false + token: ${{ secrets.ACTION_TOKEN }} + name: v${{ steps.currentTime.outputs.time }} + tag: ${{ steps.currentTime.outputs.time }} diff --git a/.gitignore b/.gitignore index 449dd0e..d41ae6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,10 @@ *.iml .gradle /local.properties -/.idea/caches/build_file_checksums.ser -/.idea/libraries -/.idea/modules.xml -/.idea/workspace.xml +/.idea/ .DS_Store /build /captures .externalNativeBuild -/.idea -.idea -*.apk -*.json \ No newline at end of file +.cxx +local.properties \ No newline at end of file diff --git a/README.md b/README.md index b09fb6b..9c36bf9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ # Activity -用于查看设备安装的所有应用的详细信息,并且可以查看当前系统顶层 Activity 的全路径,方便在反编译应用的时候快速定位 - -Apk 下载体验请看:[Releases](https://github.com/leavesCZY/Activity/releases) +用于查看系统中安装的所有应用的详细信息,且可以查看当前顶层 Activity 的全路径,方便在反编译应用的时候快速定位 \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore index d94306e..ce4a112 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,3 +1,2 @@ /build -*.apk -*.json \ No newline at end of file +/release/ \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 7152de7..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,81 +0,0 @@ -plugins { - id "com.android.application" - id "org.jetbrains.kotlin.android" -} - -static String generateBuildTime() { - return new Date().format("yyyy_MM_dd_HH_mm_ss", TimeZone.getTimeZone("Asia/Shanghai")) -} - -def keyAliasExt = "leavesCZY" -def keyPasswordExt = "123456" -def storePasswordExt = "123456" - -android { - compileSdk 33 - buildToolsVersion "33.0.2" - defaultConfig { - applicationId "github.leavesczy.activity" - minSdk 23 - targetSdk 33 - versionCode 1 - versionName "0.0.1" - resConfigs "zh" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - vectorDrawables { - useSupportLibrary true - } - applicationVariants.all { variant -> - variant.outputs.all { - outputFileName = "activity_${variant.name}_versionCode_${versionCode}_versionName_${versionName}_${generateBuildTime()}.apk" - } - } - } - signingConfigs { - releaseConfig { - storeFile file(rootDir.absolutePath + File.separator + "key.jks") - keyAlias keyAliasExt.toString() - storePassword storePasswordExt.toString() - keyPassword keyPasswordExt.toString() - v1SigningEnabled true - v2SigningEnabled true - } - } - buildTypes { - debug { - signingConfig signingConfigs.releaseConfig - minifyEnabled false - shrinkResources false - zipAlignEnabled false - debuggable true - proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" - } - release { - signingConfig signingConfigs.releaseConfig - minifyEnabled true - shrinkResources true - zipAlignEnabled true - debuggable false - proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - kotlinOptions { - jvmTarget = "1.8" - } -} - -dependencies { - testImplementation "junit:junit:4.13.2" - androidTestImplementation "androidx.test.ext:junit:1.1.4" - androidTestImplementation "androidx.test.espresso:espresso-core:3.5.0" - implementation "androidx.appcompat:appcompat:1.6.1" - implementation "androidx.constraintlayout:constraintlayout:2.1.4" - implementation "androidx.recyclerview:recyclerview:1.2.1" - implementation "com.google.android.material:material:1.8.0" - implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4" -} \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..bfc4fb7 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,103 @@ +import com.android.build.gradle.internal.api.ApkVariantOutputImpl +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale +import java.util.TimeZone + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "github.leavesczy.activity" + compileSdk = 34 + defaultConfig { + applicationId = "github.leavesczy.activity" + minSdk = 23 + targetSdk = 34 + versionCode = 1 + versionName = "1.0.0" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + applicationVariants.all { + val variant = this + outputs.all { + if (this is ApkVariantOutputImpl) { + val simpleDateFormat = SimpleDateFormat("yyyy_MM_dd_HH_mm_ss", Locale.US) + simpleDateFormat.timeZone = TimeZone.getTimeZone("Asia/Shanghai") + val currentTime = Calendar.getInstance().time + val apkBuildTime = simpleDateFormat.format(currentTime) + this.outputFileName = + "activity_${variant.name}_v${variant.versionName}_${variant.versionCode}_${apkBuildTime}.apk" + } + } + } + } + signingConfigs { + create("release") { + storeFile = + File(rootDir.absolutePath + File.separator + "doc" + File.separator + "key.jks") + keyAlias = "leavesCZY" + keyPassword = "123456" + storePassword = "123456" + enableV1Signing = true + enableV2Signing = true + } + } + buildTypes { + debug { + signingConfig = signingConfigs.getByName("release") + isMinifyEnabled = false + isShrinkResources = false + isDebuggable = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + release { + signingConfig = signingConfigs.getByName("release") + isMinifyEnabled = true + isShrinkResources = true + isDebuggable = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } + packaging { + jniLibs { + excludes += setOf("META-INF/{AL2.0,LGPL2.1}") + } + resources { + excludes += setOf( + "**/*.version", + "DebugProbesKt.bin", + "kotlin-tooling-metadata.json", + ) + } + } +} + +dependencies { + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.constraintlayout) + implementation(libs.androidx.recyclerview) + implementation(libs.androidx.lifecycle.runtime) + implementation(libs.google.material) + implementation(libs.kotlinx.coroutines) +} \ No newline at end of file diff --git a/app/dictionary.txt b/app/dictionary.txt new file mode 100644 index 0000000..139494e --- /dev/null +++ b/app/dictionary.txt @@ -0,0 +1,650 @@ +ʻ +ʼ +ʽ +ʾ +ʿ +ˆ +ˈ +ˉ +ˊ +ˋ +ˎ +ˏ +ˑ +י +ـ +ٴ +ᐧ +ᴵ +ᵎ +ᵔ +ᵢ +ⁱ +ﹳ +ﹶ +゙ +゙゙ +ᐧᐧ +ᴵᴵ +ʻʻ +ʽʽ +ʼʼ +ʿʿ +ʾʾ +ــ +ˆˆ +ˉˉ +ˈˈ +ˋˋ +ˊˊ +ˏˏ +ˎˎ +ˑˑ +ᵔᵔ +יי +ᵎᵎ +ᵢᵢ +ⁱⁱ +ﹳﹳ +ٴٴ +ﹶﹶ +ʻʼ +ʻʽ +ʻʾ +ʻʿ +ʻˆ +ʻˈ +ʻˉ +ʻˊ +ʻˋ +ʻˎ +ʻˏ +ʻˑ +ʻי +ʻـ +ʻٴ +ʻᐧ +ʻᴵ +ʻᵎ +ʻᵔ +ʻᵢ +ʻⁱ +ʻﹳ +ʻﹶ +ʻ゙ +ʼʻ +ʼʽ +ʼʾ +ʼʿ +ʼˆ +ʼˈ +ʼˉ +ʼˊ +ʼˋ +ʼˎ +ʼˏ +ʼˑ +ʼי +ʼـ +ʼٴ +ʼᐧ +ʼᴵ +ʼᵎ +ʼᵔ +ʼᵢ +ʼⁱ +ʼﹳ +ʼﹶ +ʼ゙ +ʽʻ +ʽʼ +ʽʾ +ʽʿ +ʽˆ +ʽˈ +ʽˉ +ʽˊ +ʽˋ +ʽˎ +ʽˏ +ʽˑ +ʽי +ʽـ +ʽٴ +ʽᐧ +ʽᴵ +ʽᵎ +ʽᵔ +ʽᵢ +ʽⁱ +ʽﹳ +ʽﹶ +ʽ゙ +ʾʻ +ʾʼ +ʾʽ +ʾʿ +ʾˆ +ʾˈ +ʾˉ +ʾˊ +ʾˋ +ʾˎ +ʾˏ +ʾˑ +ʾי +ʾـ +ʾٴ +ʾᐧ +ʾᴵ +ʾᵎ +ʾᵔ +ʾᵢ +ʾⁱ +ʾﹳ +ʾﹶ +ʾ゙ +ʿʻ +ʿʼ +ʿʽ +ʿʾ +ʿˆ +ʿˈ +ʿˉ +ʿˊ +ʿˋ +ʿˎ +ʿˏ +ʿˑ +ʿי +ʿـ +ʿٴ +ʿᐧ +ʿᴵ +ʿᵎ +ʿᵔ +ʿᵢ +ʿⁱ +ʿﹳ +ʿﹶ +ʿ゙ +ˆʻ +ˆʼ +ˆʽ +ˆʾ +ˆʿ +ˆˈ +ˆˉ +ˆˊ +ˆˋ +ˆˎ +ˆˏ +ˆˑ +ˆי +ˆـ +ˆٴ +ˆᐧ +ˆᴵ +ˆᵎ +ˆᵔ +ˆᵢ +ˆⁱ +ˆﹳ +ˆﹶ +ˆ゙ +ˈʻ +ˈʼ +ˈʽ +ˈʾ +ˈʿ +ˈˆ +ˈˉ +ˈˊ +ˈˋ +ˈˎ +ˈˏ +ˈˑ +ˈי +ˈـ +ˈٴ +ˈᐧ +ˈᴵ +ˈᵎ +ˈᵔ +ˈᵢ +ˈⁱ +ˈﹳ +ˈﹶ +ˈ゙ +ˉʻ +ˉʼ +ˉʽ +ˉʾ +ˉʿ +ˉˆ +ˉˈ +ˉˊ +ˉˋ +ˉˎ +ˉˏ +ˉˑ +ˉי +ˉـ +ˉٴ +ˉᐧ +ˉᴵ +ˉᵎ +ˉᵔ +ˉᵢ +ˉⁱ +ˉﹳ +ˉﹶ +ˉ゙ +ˊʻ +ˊʼ +ˊʽ +ˊʾ +ˊʿ +ˊˆ +ˊˈ +ˊˉ +ˊˋ +ˊˎ +ˊˏ +ˊˑ +ˊי +ˊـ +ˊٴ +ˊᐧ +ˊᴵ +ˊᵎ +ˊᵔ +ˊᵢ +ˊⁱ +ˊﹳ +ˊﹶ +ˊ゙ +ˋʻ +ˋʼ +ˋʽ +ˋʾ +ˋʿ +ˋˆ +ˋˈ +ˋˉ +ˋˊ +ˋˎ +ˋˏ +ˋˑ +ˋי +ˋـ +ˋٴ +ˋᐧ +ˋᴵ +ˋᵎ +ˋᵔ +ˋᵢ +ˋⁱ +ˋﹳ +ˋﹶ +ˋ゙ +ˎʻ +ˎʼ +ˎʽ +ˎʾ +ˎʿ +ˎˆ +ˎˈ +ˎˉ +ˎˊ +ˎˋ +ˎˏ +ˎˑ +ˎי +ˎـ +ˎٴ +ˎᐧ +ˎᴵ +ˎᵎ +ˎᵔ +ˎᵢ +ˎⁱ +ˎﹳ +ˎﹶ +ˎ゙ +ˏʻ +ˏʼ +ˏʽ +ˏʾ +ˏʿ +ˏˆ +ˏˈ +ˏˉ +ˏˊ +ˏˋ +ˏˎ +ˏˑ +ˏי +ˏـ +ˏٴ +ˏᐧ +ˏᴵ +ˏᵎ +ˏᵔ +ˏᵢ +ˏⁱ +ˏﹳ +ˏﹶ +ˏ゙ +ˑʻ +ˑʼ +ˑʽ +ˑʾ +ˑʿ +ˑˆ +ˑˈ +ˑˉ +ˑˊ +ˑˋ +ˑˎ +ˑˏ +ˑי +ˑـ +ˑٴ +ˑᐧ +ˑᴵ +ˑᵎ +ˑᵔ +ˑᵢ +ˑⁱ +ˑﹳ +ˑﹶ +ˑ゙ +יʻ +יʼ +יʽ +יʾ +יʿ +יˆ +יˈ +יˉ +יˊ +יˋ +יˎ +יˏ +יˑ +יـ +יٴ +יᐧ +יᴵ +יᵎ +יᵔ +יᵢ +יⁱ +יﹳ +יﹶ +י゙ +ـʻ +ـʼ +ـʽ +ـʾ +ـʿ +ـˆ +ـˈ +ـˉ +ـˊ +ـˋ +ـˎ +ـˏ +ـˑ +ـי +ـٴ +ـᐧ +ـᴵ +ـᵎ +ـᵔ +ـᵢ +ـⁱ +ـﹳ +ـﹶ +ـ゙ +ٴʻ +ٴʼ +ٴʽ +ٴʾ +ٴʿ +ٴˆ +ٴˈ +ٴˉ +ٴˊ +ٴˋ +ٴˎ +ٴˏ +ٴˑ +ٴי +ٴـ +ٴᐧ +ٴᴵ +ٴᵎ +ٴᵔ +ٴᵢ +ٴⁱ +ٴﹳ +ٴﹶ +ٴ゙ +ᐧʻ +ᐧʼ +ᐧʽ +ᐧʾ +ᐧʿ +ᐧˆ +ᐧˈ +ᐧˉ +ᐧˊ +ᐧˋ +ᐧˎ +ᐧˏ +ᐧˑ +ᐧי +ᐧـ +ᐧٴ +ᐧᴵ +ᐧᵎ +ᐧᵔ +ᐧᵢ +ᐧⁱ +ᐧﹳ +ᐧﹶ +ᐧ゙ +ᴵʻ +ᴵʼ +ᴵʽ +ᴵʾ +ᴵʿ +ᴵˆ +ᴵˈ +ᴵˉ +ᴵˊ +ᴵˋ +ᴵˎ +ᴵˏ +ᴵˑ +ᴵי +ᴵـ +ᴵٴ +ᴵᐧ +ᴵᵎ +ᴵᵔ +ᴵᵢ +ᴵⁱ +ᴵﹳ +ᴵﹶ +ᴵ゙ +ᵎʻ +ᵎʼ +ᵎʽ +ᵎʾ +ᵎʿ +ᵎˆ +ᵎˈ +ᵎˉ +ᵎˊ +ᵎˋ +ᵎˎ +ᵎˏ +ᵎˑ +ᵎי +ᵎـ +ᵎٴ +ᵎᐧ +ᵎᴵ +ᵎᵔ +ᵎᵢ +ᵎⁱ +ᵎﹳ +ᵎﹶ +ᵎ゙ +ᵔʻ +ᵔʼ +ᵔʽ +ᵔʾ +ᵔʿ +ᵔˆ +ᵔˈ +ᵔˉ +ᵔˊ +ᵔˋ +ᵔˎ +ᵔˏ +ᵔˑ +ᵔי +ᵔـ +ᵔٴ +ᵔᐧ +ᵔᴵ +ᵔᵎ +ᵔᵢ +ᵔⁱ +ᵔﹳ +ᵔﹶ +ᵔ゙ +ᵢʻ +ᵢʼ +ᵢʽ +ᵢʾ +ᵢʿ +ᵢˆ +ᵢˈ +ᵢˉ +ᵢˊ +ᵢˋ +ᵢˎ +ᵢˏ +ᵢˑ +ᵢי +ᵢـ +ᵢٴ +ᵢᐧ +ᵢᴵ +ᵢᵎ +ᵢᵔ +ᵢⁱ +ᵢﹳ +ᵢﹶ +ᵢ゙ +ⁱʻ +ⁱʼ +ⁱʽ +ⁱʾ +ⁱʿ +ⁱˆ +ⁱˈ +ⁱˉ +ⁱˊ +ⁱˋ +ⁱˎ +ⁱˏ +ⁱˑ +ⁱי +ⁱـ +ⁱٴ +ⁱᐧ +ⁱᴵ +ⁱᵎ +ⁱᵔ +ⁱᵢ +ⁱﹳ +ⁱﹶ +ⁱ゙ +ﹳʻ +ﹳʼ +ﹳʽ +ﹳʾ +ﹳʿ +ﹳˆ +ﹳˈ +ﹳˉ +ﹳˊ +ﹳˋ +ﹳˎ +ﹳˏ +ﹳˑ +ﹳי +ﹳـ +ﹳٴ +ﹳᐧ +ﹳᴵ +ﹳᵎ +ﹳᵔ +ﹳᵢ +ﹳⁱ +ﹳﹶ +ﹳ゙ +ﹶʻ +ﹶʼ +ﹶʽ +ﹶʾ +ﹶʿ +ﹶˆ +ﹶˈ +ﹶˉ +ﹶˊ +ﹶˋ +ﹶˎ +ﹶˏ +ﹶˑ +ﹶי +ﹶـ +ﹶٴ +ﹶᐧ +ﹶᴵ +ﹶᵎ +ﹶᵔ +ﹶᵢ +ﹶⁱ +ﹶﹳ +ﹶ゙ +゙ʻ +゙ʼ +゙ʽ +゙ʾ +゙ʿ +゙ˆ +゙ˈ +゙ˉ +゙ˊ +゙ˋ +゙ˎ +゙ˏ +゙ˑ +゙י +゙ـ +゙ٴ +゙ᐧ +゙ᴵ +゙ᵎ +゙ᵔ +゙ᵢ +゙ⁱ +゙ﹳ +゙ﹶ \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 7910379..ff6e98a 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# proguardFiles setting in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html @@ -19,4 +19,8 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile --optimizationpasses 10 \ No newline at end of file + +-optimizationpasses 10 +-packageobfuscationdictionary dictionary.txt +-classobfuscationdictionary dictionary.txt +-obfuscationdictionary dictionary.txt \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 313b6e8..edc4248 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ + xmlns:tools="http://schemas.android.com/tools"> + tools:ignore="DataExtractionRules,GoogleAppIndexingWarning"> diff --git a/app/src/main/java/github/leavesczy/activity/ActivityApplication.kt b/app/src/main/java/github/leavesczy/activity/ActivityApplication.kt index c8ea09e..5980bd3 100644 --- a/app/src/main/java/github/leavesczy/activity/ActivityApplication.kt +++ b/app/src/main/java/github/leavesczy/activity/ActivityApplication.kt @@ -1,7 +1,6 @@ package github.leavesczy.activity import android.app.Application -import github.leavesczy.activity.holder.ContextHolder /** * @Author: leavesCZY @@ -11,9 +10,15 @@ import github.leavesczy.activity.holder.ContextHolder */ class ActivityApplication : Application() { + companion object { + + lateinit var context: Application + + } + override fun onCreate() { super.onCreate() - ContextHolder.init(context = this) + context = this } } \ No newline at end of file diff --git a/app/src/main/java/github/leavesczy/activity/MainActivity.kt b/app/src/main/java/github/leavesczy/activity/MainActivity.kt index 0f9e532..2873816 100644 --- a/app/src/main/java/github/leavesczy/activity/MainActivity.kt +++ b/app/src/main/java/github/leavesczy/activity/MainActivity.kt @@ -11,13 +11,17 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat +import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import github.leavesczy.activity.adapter.AppRecyclerAdapter -import github.leavesczy.activity.extend.* -import github.leavesczy.activity.holder.AppInfoHolder -import github.leavesczy.activity.model.AppInfo +import github.leavesczy.activity.holder.AccessibilityUtils +import github.leavesczy.activity.holder.AccessibilityUtils.canDrawOverlays +import github.leavesczy.activity.holder.AccessibilityUtils.showToast +import github.leavesczy.activity.holder.AppInfoLoader +import github.leavesczy.activity.holder.ApplicationType +import github.leavesczy.activity.model.ApplicationDetail import github.leavesczy.activity.service.ActivityService import github.leavesczy.activity.widget.AppInfoDialog import github.leavesczy.activity.widget.CommonItemDecoration @@ -40,7 +44,7 @@ class MainActivity : AppCompatActivity() { if (canDrawOverlays) { showAccessibilityConfirmDialog() } else { - showToast("请授予悬浮窗权限") + showToast(msg = "请授予悬浮窗权限") } } @@ -48,9 +52,9 @@ class MainActivity : AppCompatActivity() { findViewById(R.id.rvAppList) } - private var appList = mutableListOf() + private var applicationDetails = mutableListOf() - private val appRecyclerAdapter = AppRecyclerAdapter(appList) + private val appRecyclerAdapter = AppRecyclerAdapter(applicationDetails) private var progressDialog: LoadingDialog? = null @@ -77,7 +81,7 @@ class MainActivity : AppCompatActivity() { appRecyclerAdapter.setOnItemClickListener(object : AppRecyclerAdapter.OnItemClickListener { override fun onItemClick(position: Int) { val fragment = AppInfoDialog() - fragment.applicationInfo = appList[position] + fragment.applicationDetail = applicationDetails[position] showDialog(fragment) } }) @@ -85,16 +89,13 @@ class MainActivity : AppCompatActivity() { @SuppressLint("NotifyDataSetChanged") private suspend fun loadApps() { - withContext(context = Dispatchers.Main.immediate) { + withContext(context = Dispatchers.Main) { startLoading() - } - withContext(context = Dispatchers.IO) { - AppInfoHolder.init(context = applicationContext) - val list = AppInfoHolder.getAllApplication() - appList.clear() - appList.addAll(list) - } - withContext(context = Dispatchers.Main.immediate) { + AppInfoLoader.init(context = applicationContext) + val list = + AppInfoLoader.filterApplications(applicationType = ApplicationType.AllApplication) + applicationDetails.clear() + applicationDetails.addAll(list) appRecyclerAdapter.notifyDataSetChanged() cancelLoading() } @@ -105,30 +106,21 @@ class MainActivity : AppCompatActivity() { return true } - @SuppressLint("NotifyDataSetChanged") override fun onOptionsItemSelected(item: MenuItem): Boolean { item.apply { when (item.itemId) { - R.id.menuAllApp, R.id.menuSystemApp, R.id.menuNormalApp -> { - val list = when (item.itemId) { - R.id.menuAllApp -> { - AppInfoHolder.getAllApplication() - } - R.id.menuSystemApp -> { - AppInfoHolder.getAllSystemApplication() - } - R.id.menuNormalApp -> { - AppInfoHolder.getAllNonSystemApplication() - } - else -> { - emptyList() - } - } - appList.clear() - appList.addAll(list) - appRecyclerAdapter.notifyDataSetChanged() - rvAppList.scrollToPosition(0) + R.id.menuAllApp -> { + filterApplications(applicationType = ApplicationType.AllApplication) } + + R.id.menuSystemApp -> { + filterApplications(applicationType = ApplicationType.SystemApplication) + } + + R.id.menuNormalApp -> { + filterApplications(applicationType = ApplicationType.NonSystemApplication) + } + R.id.menuCurrentActivity -> { if (canDrawOverlays) { requestAccessibilityPermission() @@ -141,8 +133,17 @@ class MainActivity : AppCompatActivity() { return super.onOptionsItemSelected(item) } + @SuppressLint("NotifyDataSetChanged") + private fun filterApplications(applicationType: ApplicationType) { + val applications = AppInfoLoader.filterApplications(applicationType = applicationType) + applicationDetails.clear() + applicationDetails.addAll(applications) + appRecyclerAdapter.notifyDataSetChanged() + rvAppList.scrollToPosition(0) + } + private fun requestAccessibilityPermission() { - if (accessibilityServiceIsEnabled(ActivityService::class.java)) { + if (accessibilityServiceIsEnabled()) { if (canDrawOverlays) { startActivityService() } else { @@ -155,7 +156,7 @@ class MainActivity : AppCompatActivity() { private fun requestOverlayPermission() { if (canDrawOverlays) { - if (accessibilityServiceIsEnabled(ActivityService::class.java)) { + if (accessibilityServiceIsEnabled()) { startActivityService() } else { showAccessibilityConfirmDialog() @@ -167,9 +168,11 @@ class MainActivity : AppCompatActivity() { private fun showAccessibilityConfirmDialog() { val messageDialogFragment = MessageDialogFragment() - messageDialogFragment.init("", "检测到应用似乎还未被授予无障碍服务权限,是否前往开启权限?", + messageDialogFragment.init( + "", + "检测到应用似乎还未被授予无障碍服务权限,是否前往开启权限?", { _, _ -> - navToAccessibilityServiceSettingPage() + AccessibilityUtils.navToAccessibilityServiceSettingPage(context = this) }) showDialog(messageDialogFragment) } @@ -181,13 +184,24 @@ class MainActivity : AppCompatActivity() { overlayPermissionLauncher.launch( Intent( Settings.ACTION_MANAGE_OVERLAY_PERMISSION, - Uri.parse("package:${BuildConfig.APPLICATION_ID}") + Uri.parse("package:${packageName}") ) ) }) showDialog(messageDialogFragment) } + private fun showDialog(dialogFragment: DialogFragment) { + dialogFragment.show(supportFragmentManager, dialogFragment.javaClass.name) + } + + private fun accessibilityServiceIsEnabled(): Boolean { + return AccessibilityUtils.accessibilityServiceIsEnabled( + context = this, + accessibilityService = ActivityService::class.java + ) + } + private fun startActivityService() { startService(Intent(this, ActivityService::class.java)) } diff --git a/app/src/main/java/github/leavesczy/activity/WorkflowsTrigger.kt b/app/src/main/java/github/leavesczy/activity/WorkflowsTrigger.kt new file mode 100644 index 0000000..b91eeef --- /dev/null +++ b/app/src/main/java/github/leavesczy/activity/WorkflowsTrigger.kt @@ -0,0 +1,12 @@ +package github.leavesczy.activity + +/** + * @Author: leavesCZY + * @Date: 2024/5/2 0:28 + * @Desc: + */ +object WorkflowsTrigger { + + val trigger = 1 + +} \ No newline at end of file diff --git a/app/src/main/java/github/leavesczy/activity/adapter/AppRecyclerAdapter.kt b/app/src/main/java/github/leavesczy/activity/adapter/AppRecyclerAdapter.kt index 132e176..6fc272a 100644 --- a/app/src/main/java/github/leavesczy/activity/adapter/AppRecyclerAdapter.kt +++ b/app/src/main/java/github/leavesczy/activity/adapter/AppRecyclerAdapter.kt @@ -7,7 +7,7 @@ import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import github.leavesczy.activity.R -import github.leavesczy.activity.model.AppInfo +import github.leavesczy.activity.model.ApplicationDetail /** * @Author: leavesCZY @@ -15,10 +15,10 @@ import github.leavesczy.activity.model.AppInfo * @Desc: * @Github:https://github.com/leavesCZY */ -class AppRecyclerAdapter(private val appInfoList: List) : +class AppRecyclerAdapter(private val applicationDetails: List) : RecyclerView.Adapter() { - class AppViewHolder constructor(view: View) : RecyclerView.ViewHolder(view) { + class AppViewHolder(view: View) : RecyclerView.ViewHolder(view) { val ivAppIcon: ImageView = view.findViewById(R.id.ivAppIcon) val tvAppName: TextView = view.findViewById(R.id.tvAppName) val tvAppPackageName: TextView = view.findViewById(R.id.tvAppPackageName) @@ -31,13 +31,13 @@ class AppRecyclerAdapter(private val appInfoList: List) : private var onItemClickListener: OnItemClickListener? = null override fun getItemCount(): Int { - return appInfoList.size + return applicationDetails.size } override fun onBindViewHolder(viewHolder: AppViewHolder, position: Int) { - viewHolder.ivAppIcon.setImageDrawable(appInfoList[position].icon) - viewHolder.tvAppName.text = appInfoList[position].name - viewHolder.tvAppPackageName.text = appInfoList[position].packageName + viewHolder.ivAppIcon.setImageDrawable(applicationDetails[position].icon) + viewHolder.tvAppName.text = applicationDetails[position].name + viewHolder.tvAppPackageName.text = applicationDetails[position].packageName viewHolder.itemView.setOnClickListener { onItemClickListener?.onItemClick(position) } diff --git a/app/src/main/java/github/leavesczy/activity/extend/Extend.kt b/app/src/main/java/github/leavesczy/activity/extend/Extend.kt deleted file mode 100644 index 80615b3..0000000 --- a/app/src/main/java/github/leavesczy/activity/extend/Extend.kt +++ /dev/null @@ -1,54 +0,0 @@ -package github.leavesczy.activity.extend - -import android.accessibilityservice.AccessibilityService -import android.content.* -import android.provider.Settings -import android.text.TextUtils -import android.widget.Toast -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.FragmentActivity - -/** - * @Author: leavesCZY - * @Date: 2019/8/26 12:06 - * @Desc: - * @Github:https://github.com/leavesCZY - */ -fun Context.accessibilityServiceIsEnabled(accessibilityService: Class): Boolean { - val enabledServicesSetting = - Settings.Secure.getString(contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES) - ?: return false - val colonSplitter = TextUtils.SimpleStringSplitter(':') - colonSplitter.setString(enabledServicesSetting) - while (colonSplitter.hasNext()) { - val enabledService = ComponentName.unflattenFromString(colonSplitter.next()) - if (enabledService != null && enabledService == ComponentName(this, accessibilityService)) { - return true - } - } - return false -} - -fun Context.navToAccessibilityServiceSettingPage() { - val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK - startActivity(intent) -} - -val Context.canDrawOverlays - get() = Settings.canDrawOverlays(this) - -fun Context.clipboardCopy(msg: String) { - val clipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - clipboardManager.setPrimaryClip(ClipData.newPlainText("Activity", msg)) -} - -fun Context.showToast(msg: String) { - if (msg.isNotBlank()) { - Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() - } -} - -fun FragmentActivity.showDialog(dialogFragment: DialogFragment) { - dialogFragment.show(supportFragmentManager, dialogFragment.javaClass.name) -} \ No newline at end of file diff --git a/app/src/main/java/github/leavesczy/activity/holder/AccessibilityUtils.kt b/app/src/main/java/github/leavesczy/activity/holder/AccessibilityUtils.kt new file mode 100644 index 0000000..5701275 --- /dev/null +++ b/app/src/main/java/github/leavesczy/activity/holder/AccessibilityUtils.kt @@ -0,0 +1,63 @@ +package github.leavesczy.activity.holder + +import android.accessibilityservice.AccessibilityService +import android.content.ClipData +import android.content.ClipboardManager +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.provider.Settings +import android.text.TextUtils +import android.widget.Toast + +/** + * @Author: leavesCZY + * @Date: 2024/5/4 0:49 + * @Desc: + */ +object AccessibilityUtils { + + val Context.canDrawOverlays + get() = Settings.canDrawOverlays(this) + + fun Context.clipboardCopy(msg: String) { + val clipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + clipboardManager.setPrimaryClip(ClipData.newPlainText("Activity", msg)) + } + + fun Context.showToast(msg: String) { + if (msg.isNotBlank()) { + Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() + } + } + + fun accessibilityServiceIsEnabled( + context: Context, + accessibilityService: Class + ): Boolean { + val enabledServicesSetting = Settings.Secure.getString( + context.contentResolver, + Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES + ) ?: return false + val colonSplitter = TextUtils.SimpleStringSplitter(':') + colonSplitter.setString(enabledServicesSetting) + while (colonSplitter.hasNext()) { + val enabledService = ComponentName.unflattenFromString(colonSplitter.next()) + if (enabledService != null && enabledService == ComponentName( + context, + accessibilityService + ) + ) { + return true + } + } + return false + } + + fun navToAccessibilityServiceSettingPage(context: Context) { + val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) + intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK + context.startActivity(intent) + } + +} \ No newline at end of file diff --git a/app/src/main/java/github/leavesczy/activity/holder/AppInfoHolder.kt b/app/src/main/java/github/leavesczy/activity/holder/AppInfoLoader.kt similarity index 56% rename from app/src/main/java/github/leavesczy/activity/holder/AppInfoHolder.kt rename to app/src/main/java/github/leavesczy/activity/holder/AppInfoLoader.kt index 40cee9d..61057ba 100644 --- a/app/src/main/java/github/leavesczy/activity/holder/AppInfoHolder.kt +++ b/app/src/main/java/github/leavesczy/activity/holder/AppInfoLoader.kt @@ -5,35 +5,34 @@ import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.os.Build -import github.leavesczy.activity.model.AppInfo +import github.leavesczy.activity.model.ApplicationDetail import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.security.MessageDigest /** * @Author: leavesCZY - * @Date: 2019/1/2 20:42 + * @Date: 2024/5/4 0:55 * @Desc: - * @Github:https://github.com/leavesCZY */ -object AppInfoHolder { +enum class ApplicationType { + AllApplication, + NonSystemApplication, + SystemApplication +} - private enum class ApplicationType { - AllApplication, NonSystemApplication, SystemApplication - } - - private val lock = Any() +object AppInfoLoader { - private val appCache = mutableMapOf() + private val appCache = mutableMapOf() suspend fun init(context: Context) { - withContext(context = Dispatchers.IO) { - val map = mutableMapOf() + withContext(context = Dispatchers.Default) { + val map = mutableMapOf() val packageInfoList = context.packageManager.getInstalledPackages(PackageManager.GET_SIGNATURES) for (packageInfo in packageInfoList) { val applicationInfo = packageInfo.applicationInfo - val application = AppInfo( + val applicationDetail = ApplicationDetail( packageName = packageInfo.packageName, versionName = packageInfo.versionName ?: "", targetSdkVersion = applicationInfo.targetSdkVersion, @@ -53,31 +52,35 @@ object AppInfoHolder { "" } ?: "" ) - map[application.name] = application + map[applicationDetail.name] = applicationDetail } - synchronized(lock = lock) { + synchronized(lock = this@AppInfoLoader) { appCache.clear() appCache.putAll(map) } } } - private fun getSignValidString(signatures: ByteArray): String { - val messageDigest = MessageDigest.getInstance("MD5") - messageDigest.update(signatures) - return toHexString(messageDigest.digest()) + private suspend fun getSignValidString(signatures: ByteArray): String { + return withContext(context = Dispatchers.Default) { + val messageDigest = MessageDigest.getInstance("MD5") + messageDigest.update(signatures) + return@withContext toHexString(messageDigest.digest()) + } } - private fun toHexString(keyData: ByteArray): String { - val strBuilder = StringBuilder(keyData.size * 2) - for (keyDatum in keyData) { - var hexStr = (keyDatum.toInt() and 255).toString(16) - if (hexStr.length == 1) { - hexStr = "0$hexStr" + private suspend fun toHexString(keyData: ByteArray): String { + return withContext(context = Dispatchers.Default) { + val strBuilder = StringBuilder(keyData.size * 2) + for (keyDatum in keyData) { + var hexStr = (keyDatum.toInt() and 255).toString(16) + if (hexStr.length == 1) { + hexStr = "0$hexStr" + } + strBuilder.append(hexStr) } - strBuilder.append(hexStr) + return@withContext strBuilder.toString() } - return strBuilder.toString() } private fun isSystemApplication(packageInfo: PackageInfo): Boolean { @@ -93,32 +96,24 @@ object AppInfoHolder { return "" } - private fun getApplicationInfo(applicationType: ApplicationType): List { - val applicationList = mutableListOf() - when (applicationType) { + fun filterApplications(applicationType: ApplicationType): List { + return when (applicationType) { ApplicationType.AllApplication -> { - applicationList.addAll(appCache.values) + appCache.values.toList() } + ApplicationType.SystemApplication -> { - applicationList.addAll(appCache.filter { entry -> entry.value.isSystemApp }.values) + appCache.values.filter { + it.isSystemApp + } } + ApplicationType.NonSystemApplication -> { - applicationList.addAll(appCache.filter { entry -> !entry.value.isSystemApp }.values) + appCache.values.filter { + !it.isSystemApp + } } } - return applicationList - } - - fun getAllApplication(): List { - return getApplicationInfo(ApplicationType.AllApplication) - } - - fun getAllSystemApplication(): List { - return getApplicationInfo(ApplicationType.SystemApplication) - } - - fun getAllNonSystemApplication(): List { - return getApplicationInfo(ApplicationType.NonSystemApplication) } } \ No newline at end of file diff --git a/app/src/main/java/github/leavesczy/activity/holder/ContextHolder.kt b/app/src/main/java/github/leavesczy/activity/holder/ContextHolder.kt deleted file mode 100644 index f7cd8fc..0000000 --- a/app/src/main/java/github/leavesczy/activity/holder/ContextHolder.kt +++ /dev/null @@ -1,22 +0,0 @@ -package github.leavesczy.activity.holder - -import android.annotation.SuppressLint -import android.content.Context - -/** - * @Author: leavesCZY - * @Date: 2019/1/17 23:36 - * @Desc: - * @Github:https://github.com/leavesCZY - */ -@SuppressLint("StaticFieldLeak") -object ContextHolder { - - lateinit var context: Context - private set - - fun init(context: Context) { - this.context = context - } - -} \ No newline at end of file diff --git a/app/src/main/java/github/leavesczy/activity/model/AppInfo.kt b/app/src/main/java/github/leavesczy/activity/model/ApplicationDetail.kt similarity index 91% rename from app/src/main/java/github/leavesczy/activity/model/AppInfo.kt rename to app/src/main/java/github/leavesczy/activity/model/ApplicationDetail.kt index 1a22121..3ced70f 100644 --- a/app/src/main/java/github/leavesczy/activity/model/AppInfo.kt +++ b/app/src/main/java/github/leavesczy/activity/model/ApplicationDetail.kt @@ -3,10 +3,11 @@ package github.leavesczy.activity.model import android.graphics.drawable.Drawable import android.text.TextUtils import android.text.format.Formatter -import github.leavesczy.activity.holder.ContextHolder +import github.leavesczy.activity.ActivityApplication import java.io.File import java.text.SimpleDateFormat -import java.util.* +import java.util.Date +import java.util.Locale /** * @Author: leavesCZY @@ -14,7 +15,7 @@ import java.util.* * @Desc: * @Github:https://github.com/leavesCZY */ -data class AppInfo( +data class ApplicationDetail( val name: String, val packageName: String, val icon: Drawable, @@ -81,7 +82,7 @@ data class AppInfo( val size = if (TextUtils.isEmpty(sourceDir)) { "" } else { - Formatter.formatShortFileSize(ContextHolder.context, File(sourceDir).length()) + Formatter.formatShortFileSize(ActivityApplication.context, File(sourceDir).length()) } return "apkSize:$size" } diff --git a/app/src/main/java/github/leavesczy/activity/service/ActivityService.kt b/app/src/main/java/github/leavesczy/activity/service/ActivityService.kt index 09f9e48..1a769d2 100644 --- a/app/src/main/java/github/leavesczy/activity/service/ActivityService.kt +++ b/app/src/main/java/github/leavesczy/activity/service/ActivityService.kt @@ -6,7 +6,12 @@ import android.content.Context import android.content.Intent import android.os.Build import android.util.Log -import android.view.* +import android.view.Gravity +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager import android.view.accessibility.AccessibilityEvent import android.widget.ImageView import android.widget.TextView @@ -15,10 +20,10 @@ import androidx.recyclerview.widget.RecyclerView import github.leavesczy.activity.R import github.leavesczy.activity.adapter.ActivityRecyclerAdapter import github.leavesczy.activity.adapter.AppRecyclerAdapter -import github.leavesczy.activity.extend.canDrawOverlays -import github.leavesczy.activity.extend.clipboardCopy -import github.leavesczy.activity.extend.showToast -import github.leavesczy.activity.holder.AppInfoHolder +import github.leavesczy.activity.holder.AccessibilityUtils.canDrawOverlays +import github.leavesczy.activity.holder.AccessibilityUtils.clipboardCopy +import github.leavesczy.activity.holder.AccessibilityUtils.showToast +import github.leavesczy.activity.holder.AppInfoLoader /** * @Author: leavesCZY @@ -28,12 +33,6 @@ import github.leavesczy.activity.holder.AppInfoHolder */ class ActivityService : AccessibilityService() { - companion object { - - private const val TAG = "ActivityService" - - } - private var windowView: View? = null private var tvAppName: TextView? = null @@ -53,12 +52,16 @@ class ActivityService : AccessibilityService() { override fun onServiceConnected() { super.onServiceConnected() showFloatingWindow() - Log.e(TAG, "onServiceConnected()") + log { + "onServiceConnected()" + } } - @SuppressLint("SetTextI18n", "NotifyDataSetChanged") + @SuppressLint("NotifyDataSetChanged") override fun onAccessibilityEvent(event: AccessibilityEvent?) { - Log.e(TAG, "onAccessibilityEvent()") + log { + "onAccessibilityEvent()" + } windowView?.let { event?.let { val eventType = event.eventType @@ -67,9 +70,13 @@ class ActivityService : AccessibilityService() { val appName = if (packageName.isBlank()) { "" } else { - AppInfoHolder.getAppName(packageName) + AppInfoLoader.getAppName(packageName) + } + tvAppName?.text = buildString { + append(appName) + append(" : ") + append(packageName) } - tvAppName?.text = "$appName : $packageName" event.className?.let { activityList.add("${++itemIndex}" + " : " + event.className.toString()) rvActivityList?.scrollToPosition( @@ -83,12 +90,16 @@ class ActivityService : AccessibilityService() { } override fun onInterrupt() { - Log.e(TAG, "onInterrupt()") + log { + "onInterrupt()" + } removeWindow() } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Log.e(TAG, "onStartCommand()") + log { + "onStartCommand()" + } showFloatingWindow() return super.onStartCommand(intent, flags, startId) } @@ -96,7 +107,9 @@ class ActivityService : AccessibilityService() { override fun onDestroy() { super.onDestroy() removeWindow() - Log.e(TAG, "onDestroy()") + log { + "onDestroy()" + } } private fun removeWindow() { @@ -116,7 +129,6 @@ class ActivityService : AccessibilityService() { } } - @SuppressLint("ClickableViewAccessibility") private fun initView() { val layoutView = LayoutInflater.from(this).inflate(R.layout.layout_activity_window, null) val ivExtendsWindow = layoutView.findViewById(R.id.ivExtendsWindow) @@ -144,8 +156,8 @@ class ActivityService : AccessibilityService() { AppRecyclerAdapter.OnItemClickListener { override fun onItemClick(position: Int) { val text = tvAppName.text.toString() + "\n" + activityList[position] - clipboardCopy(text) - showToast("已复制进程&页面信息") + clipboardCopy(msg = text) + showToast(msg = "已复制进程&页面信息") } }) rvActivityList.adapter = activityRecyclerAdapter @@ -181,6 +193,7 @@ class ActivityService : AccessibilityService() { x = event.rawX.toInt() y = event.rawY.toInt() } + MotionEvent.ACTION_MOVE -> { val nowX = event.rawX.toInt() val nowY = event.rawY.toInt() @@ -188,8 +201,8 @@ class ActivityService : AccessibilityService() { val movedY = nowY - y x = nowX y = nowY - layoutParams.x = layoutParams.x + movedX - layoutParams.y = layoutParams.y + movedY + layoutParams.x += movedX + layoutParams.y += movedY windowManager.updateViewLayout(view, layoutParams) } } @@ -197,4 +210,8 @@ class ActivityService : AccessibilityService() { } } + private fun log(log: () -> Any) { + Log.e("ActivityService", log().toString()) + } + } \ No newline at end of file diff --git a/app/src/main/java/github/leavesczy/activity/widget/AppInfoDialog.kt b/app/src/main/java/github/leavesczy/activity/widget/AppInfoDialog.kt index c1e7677..a974a54 100644 --- a/app/src/main/java/github/leavesczy/activity/widget/AppInfoDialog.kt +++ b/app/src/main/java/github/leavesczy/activity/widget/AppInfoDialog.kt @@ -12,9 +12,9 @@ import android.widget.ImageView import android.widget.TextView import androidx.appcompat.app.AppCompatDialogFragment import github.leavesczy.activity.R -import github.leavesczy.activity.extend.clipboardCopy -import github.leavesczy.activity.extend.showToast -import github.leavesczy.activity.model.AppInfo +import github.leavesczy.activity.holder.AccessibilityUtils.clipboardCopy +import github.leavesczy.activity.holder.AccessibilityUtils.showToast +import github.leavesczy.activity.model.ApplicationDetail /** * @Author: leavesCZY @@ -24,7 +24,7 @@ import github.leavesczy.activity.model.AppInfo */ class AppInfoDialog : AppCompatDialogFragment() { - var applicationInfo: AppInfo? = null + var applicationDetail: ApplicationDetail? = null init { setStyle(STYLE_NO_TITLE, 0) @@ -41,7 +41,7 @@ class AppInfoDialog : AppCompatDialogFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val mApplicationInfo = applicationInfo + val mApplicationInfo = applicationDetail if (mApplicationInfo == null) { dismiss() return @@ -72,8 +72,8 @@ class AppInfoDialog : AppCompatDialogFragment() { view.findViewById(R.id.ivAppCopy).setOnClickListener { val context = activity context?.let { - it.clipboardCopy(mApplicationInfo.toString()) - it.showToast("已复制应用信息") + it.clipboardCopy(msg = mApplicationInfo.toString()) + it.showToast(msg = "已复制应用信息") } } } diff --git a/app/src/main/java/github/leavesczy/activity/widget/CommonItemDecoration.kt b/app/src/main/java/github/leavesczy/activity/widget/CommonItemDecoration.kt index bb32347..c2cd538 100644 --- a/app/src/main/java/github/leavesczy/activity/widget/CommonItemDecoration.kt +++ b/app/src/main/java/github/leavesczy/activity/widget/CommonItemDecoration.kt @@ -42,10 +42,6 @@ class CommonItemDecoration(private var drawable: Drawable, private var orientati private fun drawVerticalDivider(c: Canvas, parent: RecyclerView) { for (i in 0 until parent.childCount) { val child = parent.getChildAt(i) - //RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); - //受 child layout_marginEnd 属性的影响 - //int left = child.getRight() + params.rightMargin; - //不受 child layout_marginEnd 属性的影响,会直接绘制在 child 右侧 val left = child.right val top = child.top val right = left + drawable.intrinsicWidth @@ -59,13 +55,9 @@ class CommonItemDecoration(private var drawable: Drawable, private var orientati for (i in 0 until parent.childCount) { val child = parent.getChildAt(i) val left = child.left - //不受 child layout_marginBottom 属性的影响,会直接绘制在 child 底部 val top = child.bottom val right = child.right val bottom = top + drawable.intrinsicHeight - //会受 child layout_marginBottom 属性的影响 - //RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); - //int top = child.getBottom() + params.bottomMargin; drawable.setBounds(left, top, right, bottom) drawable.draw(c) } diff --git a/app/src/main/res/drawable/icon_copy.png b/app/src/main/res/drawable/icon_copy.png deleted file mode 100644 index fe33b73..0000000 Binary files a/app/src/main/res/drawable/icon_copy.png and /dev/null differ diff --git a/app/src/main/res/drawable/icon_copy.webp b/app/src/main/res/drawable/icon_copy.webp new file mode 100644 index 0000000..cf40394 Binary files /dev/null and b/app/src/main/res/drawable/icon_copy.webp differ diff --git a/app/src/main/res/drawable/icon_extends_window.png b/app/src/main/res/drawable/icon_extends_window.png deleted file mode 100644 index 2fe885e..0000000 Binary files a/app/src/main/res/drawable/icon_extends_window.png and /dev/null differ diff --git a/app/src/main/res/drawable/icon_extends_window.webp b/app/src/main/res/drawable/icon_extends_window.webp new file mode 100644 index 0000000..e7942f2 Binary files /dev/null and b/app/src/main/res/drawable/icon_extends_window.webp differ diff --git a/app/src/main/res/drawable/icon_loading.png b/app/src/main/res/drawable/icon_loading.png deleted file mode 100644 index 393e0d5..0000000 Binary files a/app/src/main/res/drawable/icon_loading.png and /dev/null differ diff --git a/app/src/main/res/drawable/icon_loading.webp b/app/src/main/res/drawable/icon_loading.webp new file mode 100644 index 0000000..0e7759e Binary files /dev/null and b/app/src/main/res/drawable/icon_loading.webp differ diff --git a/app/src/main/res/drawable/icon_remove_window.png b/app/src/main/res/drawable/icon_remove_window.png deleted file mode 100644 index c631dd8..0000000 Binary files a/app/src/main/res/drawable/icon_remove_window.png and /dev/null differ diff --git a/app/src/main/res/drawable/icon_remove_window.webp b/app/src/main/res/drawable/icon_remove_window.webp new file mode 100644 index 0000000..225b355 Binary files /dev/null and b/app/src/main/res/drawable/icon_remove_window.webp differ diff --git a/app/src/main/res/drawable/icon_settings.png b/app/src/main/res/drawable/icon_settings.png deleted file mode 100644 index f3b082b..0000000 Binary files a/app/src/main/res/drawable/icon_settings.png and /dev/null differ diff --git a/app/src/main/res/drawable/icon_settings.webp b/app/src/main/res/drawable/icon_settings.webp new file mode 100644 index 0000000..7dba563 Binary files /dev/null and b/app/src/main/res/drawable/icon_settings.webp differ diff --git a/app/src/main/res/layout/layout_activity_window.xml b/app/src/main/res/layout/layout_activity_window.xml index 877205c..20413fb 100644 --- a/app/src/main/res/layout/layout_activity_window.xml +++ b/app/src/main/res/layout/layout_activity_window.xml @@ -18,13 +18,13 @@ android:layout_height="wrap_content" android:layout_weight="1" android:ellipsize="end" - android:maxLines="2" + android:maxLines="3" android:paddingStart="16dp" android:paddingTop="8dp" android:paddingEnd="16dp" android:paddingBottom="8dp" android:textColor="@android:color/white" - tools:text="当前应用名当前应用名" /> + tools:text="当前应用名" /> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + app:showAsAction="never" + tools:ignore="HardcodedText" /> + app:showAsAction="never" + tools:ignore="HardcodedText" /> + app:showAsAction="never" + tools:ignore="HardcodedText" /> + app:showAsAction="never" + tools:ignore="HardcodedText" /> diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..fc03d9b Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9339542 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..fc03d9b Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9339542 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..fc03d9b Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..9339542 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap/ic_launcher.png b/app/src/main/res/mipmap/ic_launcher.png deleted file mode 100644 index 1c573f4..0000000 Binary files a/app/src/main/res/mipmap/ic_launcher.png and /dev/null differ diff --git a/app/src/main/res/mipmap/ic_launcher_round.png b/app/src/main/res/mipmap/ic_launcher_round.png deleted file mode 100644 index 6ca507b..0000000 Binary files a/app/src/main/res/mipmap/ic_launcher_round.png and /dev/null differ diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml deleted file mode 100644 index 8f51ac2..0000000 --- a/app/src/main/res/xml/data_extraction_rules.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/build.gradle b/build.gradle deleted file mode 100644 index d19d675..0000000 --- a/build.gradle +++ /dev/null @@ -1,10 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. -plugins { - id 'com.android.application' version '7.4.1' apply false - id 'com.android.library' version '7.4.1' apply false - id 'org.jetbrains.kotlin.android' version '1.8.10' apply false -} - -task clean(type: Delete) { - delete rootProject.buildDir -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..76a6204 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,4 @@ +plugins { + alias(libs.plugins.android.application).apply(false) + alias(libs.plugins.kotlin.android).apply(false) +} \ No newline at end of file diff --git a/key.jks b/doc/key.jks similarity index 100% rename from key.jks rename to doc/key.jks diff --git a/gradle.properties b/gradle.properties index 9bfda47..37ae531 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,11 +8,20 @@ # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# This option should only be used with decoupled projects. For more details, visit +# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects # org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true # Kotlin code style for this project: "official" or "obsolete": kotlin.code.style=official -android.useAndroidX=true -android.enableJetifier=true -android.enableR8.fullMode=true \ No newline at end of file +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonFinalResIds=true +android.nonTransitiveRClass=true +android.enableR8.fullMode=true +android.defaults.buildfeatures.resvalues=false +android.defaults.buildfeatures.shaders=false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..a40fdac --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,35 @@ +[versions] +android-plugin = "8.4.0" +kotlin-plugin = "1.9.23" + +junit = "4.13.2" +androidx-junit = "1.1.5" +androidx-espresso = "3.5.1" + +androidx-appcompat = "1.6.1" +androidx-constraintlayout = "2.1.4" +androidx-recyclerview = "1.3.2" +androidx-lifecycle-runtime = "2.7.0" + +google-material = "1.12.0" + +kotlinx-coroutines = "1.8.0" + +[libraries] +androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" } +androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-espresso" } + +androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } +androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle-runtime" } +androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerview" } +androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx-constraintlayout" } + +google-material = { module = "com.google.android.material:material", version.ref = "google-material" } + +kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" } + +junit = { module = "junit:junit", version.ref = "junit" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "android-plugin" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin-plugin" } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 90563db..e846b64 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Jul 26 21:29:26 CST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME \ No newline at end of file +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/gradlew b/gradlew index cccdd3d..3a163de 100644 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -66,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -109,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" +exec "$JAVACMD" "$@" \ No newline at end of file diff --git a/gradlew.bat b/gradlew.bat index f955316..477c896 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell @@ -81,4 +86,4 @@ exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal -:omega +:omega \ No newline at end of file diff --git a/settings.gradle b/settings.gradle.kts similarity index 51% rename from settings.gradle rename to settings.gradle.kts index 6200a2d..bfed888 100644 --- a/settings.gradle +++ b/settings.gradle.kts @@ -1,8 +1,16 @@ +@file:Suppress("UnstableApiUsage") + pluginManagement { repositories { - gradlePluginPortal() - google() + google { + content { + includeGroupByRegex("com\\.android.*") + includeGroupByRegex("com\\.google.*") + includeGroupByRegex("androidx.*") + } + } mavenCentral() + gradlePluginPortal() } } dependencyResolutionManagement { @@ -12,5 +20,6 @@ dependencyResolutionManagement { mavenCentral() } } + rootProject.name = "Activity" -include ':app' \ No newline at end of file +include(":app") \ No newline at end of file