├── sample ├── .gitignore ├── src │ └── main │ │ ├── ic_launcher-playstore.png │ │ ├── res │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── values │ │ │ ├── colors.xml │ │ │ ├── styles.xml │ │ │ └── strings.xml │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── drawable-v24 │ │ │ ├── ic_launcher_monochrome.xml │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout │ │ │ └── activity_main.xml │ │ └── drawable │ │ │ └── ic_launcher_background.xml │ │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── venom │ │ │ └── sample │ │ │ ├── App.kt │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml └── build.gradle ├── venom ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── drawable-hdpi │ │ │ │ └── venom_dead_robot.png │ │ │ ├── drawable-mdpi │ │ │ │ └── venom_dead_robot.png │ │ │ ├── drawable-xhdpi │ │ │ │ └── venom_dead_robot.png │ │ │ ├── drawable-xxhdpi │ │ │ │ └── venom_dead_robot.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ └── venom_dead_robot.png │ │ │ ├── values │ │ │ │ ├── styles.xml │ │ │ │ ├── colors.xml │ │ │ │ └── strings.xml │ │ │ └── drawable │ │ │ │ ├── venom_death_bg.xml │ │ │ │ └── android_adb.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── github │ │ │ │ └── venom │ │ │ │ ├── service │ │ │ │ ├── ServiceDelegate.kt │ │ │ │ ├── NotificationConfig.kt │ │ │ │ ├── VenomService.kt │ │ │ │ └── VenomNotificationManager.kt │ │ │ │ ├── VenomPreferenceManager.kt │ │ │ │ ├── CompositionRoot.kt │ │ │ │ ├── Venom.kt │ │ │ │ └── DeathActivity.kt │ │ └── AndroidManifest.xml │ ├── androidTest │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── venom │ │ │ └── test │ │ │ ├── VenomTestActivity.kt │ │ │ └── VenomTest.kt │ └── test │ │ └── java │ │ └── com │ │ └── github │ │ └── venom │ │ ├── service │ │ └── ServiceDelegateTest.kt │ │ └── VenomTest.kt └── build.gradle ├── venom-no-op ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── github │ │ └── venom │ │ ├── Venom.kt │ │ └── service │ │ └── NotificationConfig.kt └── build.gradle ├── preview ├── header.png ├── preview.gif └── preview.mp4 ├── detekt-config.yml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .editorconfig ├── jitpack.yml ├── .gitignore ├── .github └── workflows │ ├── check.yml │ └── build.yml ├── LICENSE ├── settings.gradle ├── gradle.properties ├── static-analysis.gradle ├── common-android.gradle ├── gradlew.bat ├── README.md └── gradlew /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /venom/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /venom-no-op/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /preview/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/preview/header.png -------------------------------------------------------------------------------- /preview/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/preview/preview.gif -------------------------------------------------------------------------------- /preview/preview.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/preview/preview.mp4 -------------------------------------------------------------------------------- /detekt-config.yml: -------------------------------------------------------------------------------- 1 | build: 2 | maxIssues: 1 3 | 4 | complexity: 5 | TooManyFunctions: 6 | thresholdInClasses: 15 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{kt,kts}] 2 | ij_kotlin_allow_trailing_comma_on_call_site = false 3 | ij_kotlin_allow_trailing_comma = false 4 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk17 3 | before_install: 4 | - sdk install java 17.0.1-open 5 | - sdk use java 17.0.1-open 6 | -------------------------------------------------------------------------------- /sample/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea** 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | .cxx 10 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /venom/src/main/res/drawable-hdpi/venom_dead_robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/venom/src/main/res/drawable-hdpi/venom_dead_robot.png -------------------------------------------------------------------------------- /venom/src/main/res/drawable-mdpi/venom_dead_robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/venom/src/main/res/drawable-mdpi/venom_dead_robot.png -------------------------------------------------------------------------------- /venom/src/main/res/drawable-xhdpi/venom_dead_robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/venom/src/main/res/drawable-xhdpi/venom_dead_robot.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/sample/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /venom/src/main/res/drawable-xxhdpi/venom_dead_robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/venom/src/main/res/drawable-xxhdpi/venom_dead_robot.png -------------------------------------------------------------------------------- /venom/src/main/res/drawable-xxxhdpi/venom_dead_robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YarikSOffice/venom/HEAD/venom/src/main/res/drawable-xxxhdpi/venom_dead_robot.png -------------------------------------------------------------------------------- /sample/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #6200EE 4 | #3700B3 5 | #03DAC5 6 | -------------------------------------------------------------------------------- /venom/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Aug 12 13:32:49 CEST 2023 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /sample/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | -------------------------------------------------------------------------------- /venom/src/main/res/drawable/venom_death_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /sample/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /sample/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Venom 3 | Process ID: %d 4 | Screen # %d 5 | Next Activity 6 | Start Venom 7 | Stop Venom 8 | Kill 9 | Cancel 10 | -------------------------------------------------------------------------------- /venom/src/main/res/drawable/android_adb.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample/src/main/java/com/github/venom/sample/App.kt: -------------------------------------------------------------------------------- 1 | package com.github.venom.sample 2 | 3 | import android.app.Application 4 | import com.github.venom.Venom 5 | import com.github.venom.service.NotificationConfig 6 | 7 | class App : Application() { 8 | 9 | override fun onCreate() { 10 | super.onCreate() 11 | val venom = Venom.createInstance(this) 12 | 13 | val notification = NotificationConfig.Builder(this) 14 | .buttonCancel(R.string.venom_notification_button_cancel_override) 15 | .buttonKill(getString(R.string.venom_notification_button_kill_override)) 16 | .build() 17 | venom.initialize(notification) 18 | Venom.setGlobalInstance(venom) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Check 2 | 3 | on: 4 | push: 5 | branches-ignore: 6 | - master 7 | 8 | pull_request: 9 | branches-ignore: 10 | - master 11 | 12 | jobs: 13 | jvm: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v2 19 | 20 | - name: Setup Gradle 21 | uses: gradle/gradle-build-action@v2.2.2 22 | with: 23 | cache-read-only: ${{ github.ref != 'refs/heads/master' }} 24 | 25 | - name: Validate Gradle wrapper 26 | uses: gradle/wrapper-validation-action@v1 27 | 28 | - name: Configure JDK 29 | uses: actions/setup-java@v1 30 | with: 31 | java-version: 17 32 | 33 | - name: Run all checks 34 | run: ./gradlew check --stacktrace 35 | -------------------------------------------------------------------------------- /venom/src/main/java/com/github/venom/service/ServiceDelegate.kt: -------------------------------------------------------------------------------- 1 | package com.github.venom.service 2 | 3 | import android.app.ActivityManager 4 | import android.content.Context 5 | import android.content.Intent 6 | import androidx.core.content.ContextCompat 7 | 8 | internal class ServiceDelegate(private val context: Context) { 9 | 10 | fun startService() { 11 | if (!isServiceRunning()) { 12 | ContextCompat.startForegroundService(context, Intent(context, VenomService::class.java)) 13 | } 14 | } 15 | 16 | fun stopService() { 17 | context.stopService(Intent(context, VenomService::class.java)) 18 | } 19 | 20 | @Suppress("DEPRECATION") 21 | fun isServiceRunning(): Boolean { 22 | val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager 23 | return manager.getRunningServices(Integer.MAX_VALUE) 24 | .any { it.service.className == VenomService::class.java.name } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v24/ic_launcher_monochrome.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 13 | -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2020 Yaroslav Berezanskyi 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 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | include ':venom' 26 | include ':venom-no-op' 27 | include ':sample' 28 | rootProject.name = "Venom" 29 | -------------------------------------------------------------------------------- /venom-no-op/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | 23 | android.defaults.buildfeatures.buildconfig=true 24 | android.nonTransitiveRClass=false 25 | android.nonFinalResIds=false 26 | -------------------------------------------------------------------------------- /venom/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | #512DA8 27 | #404040 28 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | pull_request: 9 | branches: 10 | - master 11 | 12 | jobs: 13 | jvm: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v2 19 | 20 | - name: Setup Gradle 21 | uses: gradle/gradle-build-action@v2.2.2 22 | with: 23 | cache-read-only: ${{ github.ref != 'refs/heads/master' }} 24 | 25 | - name: Validate Gradle wrapper 26 | uses: gradle/wrapper-validation-action@v1 27 | 28 | - name: Configure JDK 29 | uses: actions/setup-java@v1 30 | with: 31 | java-version: 17 32 | 33 | - name: Assemble and test 34 | run: ./gradlew build --stacktrace 35 | 36 | android: 37 | runs-on: macos-latest 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | - name: Setup Gradle 44 | uses: gradle/gradle-build-action@v2.2.2 45 | with: 46 | cache-read-only: ${{ github.ref != 'refs/heads/master' }} 47 | 48 | - name: Validate Gradle wrapper 49 | uses: gradle/wrapper-validation-action@v1 50 | 51 | - name: Configure JDK 52 | uses: actions/setup-java@v1 53 | with: 54 | java-version: 17 55 | 56 | - name: Run all device checks 57 | uses: reactivecircus/android-emulator-runner@v2 58 | with: 59 | api-level: 29 60 | script: ./gradlew connectedCheck --stacktrace 61 | -------------------------------------------------------------------------------- /venom/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | Kill 27 | Restart 28 | Cancel 29 | Venom Service 30 | Running and ready to kill 31 | 32 | -------------------------------------------------------------------------------- /static-analysis.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | apply plugin: "io.gitlab.arturbosch.detekt" 26 | apply plugin: "org.jlleitschuh.gradle.ktlint" 27 | 28 | android { 29 | lint { 30 | disable 'GradleDependency' 31 | warningsAsErrors true 32 | abortOnError true 33 | } 34 | } 35 | 36 | ktlint { 37 | version = rootProject.ext.ktlintVersion 38 | enableExperimentalRules = true 39 | } 40 | 41 | detekt { 42 | config = files("../detekt-config.yml") 43 | buildUponDefaultConfig = true 44 | } 45 | -------------------------------------------------------------------------------- /venom-no-op/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | apply plugin: 'com.android.library' 26 | apply plugin: 'kotlin-android' 27 | apply from: '../common-android.gradle' 28 | apply from: '../static-analysis.gradle' 29 | 30 | android.namespace 'com.github.venom' 31 | 32 | dependencies { 33 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 34 | } 35 | 36 | project.afterEvaluate { 37 | publishing { 38 | publications { 39 | release(MavenPublication) { 40 | from components.release 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /sample/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | 31 | -------------------------------------------------------------------------------- /common-android.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | apply plugin: "maven-publish" 26 | 27 | android { 28 | compileSdkVersion rootProject.ext.compileSdkVersion 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_17 31 | targetCompatibility JavaVersion.VERSION_17 32 | } 33 | kotlinOptions { 34 | jvmTarget = JavaVersion.VERSION_17 35 | } 36 | 37 | defaultConfig { 38 | minSdkVersion rootProject.ext.minSdkVersion 39 | targetSdkVersion rootProject.ext.targetSdkVersion 40 | versionName rootProject.ext.versionName 41 | 42 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | apply plugin: 'com.android.application' 26 | apply plugin: 'kotlin-android' 27 | apply from: '../static-analysis.gradle' 28 | apply from: '../common-android.gradle' 29 | 30 | android { 31 | defaultConfig.applicationId 'com.github.venom.sample' 32 | namespace 'com.github.venom.sample' 33 | } 34 | 35 | dependencies { 36 | debugImplementation project(":venom") 37 | releaseImplementation project(":venom-no-op") 38 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 39 | implementation "androidx.appcompat:appcompat:$appCompatVersion" 40 | implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion" 41 | } 42 | -------------------------------------------------------------------------------- /venom/src/androidTest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /venom/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 37 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /venom/src/main/java/com/github/venom/VenomPreferenceManager.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.venom 26 | 27 | import android.content.Context 28 | import android.content.Context.MODE_PRIVATE 29 | import android.content.SharedPreferences 30 | 31 | internal class VenomPreferenceManager(context: Context) { 32 | 33 | private val preference: SharedPreferences = 34 | context.getSharedPreferences(PREFERENCE_NAME, MODE_PRIVATE) 35 | 36 | fun setActive(active: Boolean) { 37 | preference.edit().putBoolean(ACTIVE_KEY, active).apply() 38 | } 39 | 40 | fun isActive(): Boolean { 41 | return preference.getBoolean(ACTIVE_KEY, false) 42 | } 43 | 44 | companion object { 45 | private const val PREFERENCE_NAME = "venom" 46 | private const val ACTIVE_KEY = "active_key" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /venom/src/main/java/com/github/venom/CompositionRoot.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.venom 26 | 27 | import android.content.Context 28 | import com.github.venom.service.ServiceDelegate 29 | import com.github.venom.service.VenomNotificationManager 30 | 31 | internal class CompositionRoot private constructor(context: Context) { 32 | val notificationManager = VenomNotificationManager(context) 33 | val preferenceManager = VenomPreferenceManager(context) 34 | val serviceDelegate = ServiceDelegate(context) 35 | 36 | companion object { 37 | private lateinit var root: CompositionRoot 38 | 39 | fun getCompositionRoot(context: Context): CompositionRoot { 40 | if (!::root.isInitialized) { 41 | root = CompositionRoot(context) 42 | } 43 | return root 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /venom-no-op/src/main/java/com/github/venom/Venom.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("unused") 26 | 27 | package com.github.venom 28 | 29 | import android.content.Context 30 | import com.github.venom.service.NotificationConfig 31 | 32 | @Suppress("UNUSED_PARAMETER") 33 | class Venom private constructor() { 34 | 35 | @JvmOverloads 36 | fun initialize(config: NotificationConfig? = null) { 37 | // No-op 38 | } 39 | 40 | fun start() { 41 | // No-op 42 | } 43 | 44 | fun stop() { 45 | // No-op 46 | } 47 | 48 | @Suppress("FunctionOnlyReturningConstant") 49 | fun isRunning() = false 50 | 51 | companion object { 52 | 53 | @JvmStatic 54 | fun createInstance(ignored: Context) = Venom() 55 | 56 | @JvmStatic 57 | fun setGlobalInstance(ignored: Venom) { 58 | // No-op 59 | } 60 | 61 | @JvmStatic 62 | fun getGlobalInstance() = Venom() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /sample/src/main/java/com/github/venom/sample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.github.venom.sample 2 | 3 | import android.Manifest.permission.POST_NOTIFICATIONS 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.os.Build 7 | import android.os.Bundle 8 | import android.os.Process 9 | import android.view.View 10 | import android.widget.TextView 11 | import androidx.activity.result.contract.ActivityResultContracts.RequestPermission 12 | import androidx.appcompat.app.AppCompatActivity 13 | import com.github.venom.Venom 14 | 15 | class MainActivity : AppCompatActivity() { 16 | 17 | private val venom = Venom.getGlobalInstance() 18 | 19 | private val permissionLauncher = registerForActivityResult(RequestPermission()) { isGranted -> 20 | if (isGranted) { 21 | venom.start() 22 | } 23 | } 24 | 25 | override fun onCreate(savedInstanceState: Bundle?) { 26 | super.onCreate(savedInstanceState) 27 | setContentView(R.layout.activity_main) 28 | 29 | val number = intent.getIntExtra(NUMBER_ARG, 1) 30 | 31 | findViewById(R.id.pid).text = getString(R.string.pid, Process.myPid()) 32 | findViewById(R.id.label).text = getString(R.string.venom_screen_label, number) 33 | findViewById(R.id.next_activity).setOnClickListener { 34 | launch(this, number + 1) 35 | } 36 | findViewById(R.id.start).setOnClickListener { 37 | verifyNotificationPermissionAndLaunchVenom() 38 | } 39 | findViewById(R.id.stop).setOnClickListener { 40 | venom.stop() 41 | } 42 | } 43 | 44 | private fun verifyNotificationPermissionAndLaunchVenom() { 45 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { 46 | venom.start() 47 | } else { 48 | permissionLauncher.launch(POST_NOTIFICATIONS) 49 | } 50 | } 51 | 52 | companion object { 53 | private const val NUMBER_ARG = "number_arg" 54 | 55 | fun launch(context: Context, number: Int) { 56 | val intent = Intent(context, MainActivity::class.java) 57 | .putExtra(NUMBER_ARG, number) 58 | context.startActivity(intent) 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /venom-no-op/src/main/java/com/github/venom/service/NotificationConfig.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("unused") 26 | 27 | package com.github.venom.service 28 | 29 | import android.content.Context 30 | 31 | @Suppress("DataClassPrivateConstructor", "UNUSED_PARAMETER") 32 | data class NotificationConfig private constructor( 33 | val title: String, 34 | val text: String, 35 | val buttonKill: String, 36 | val buttonCancel: String, 37 | val iconRes: Int, 38 | val colorRes: Int 39 | ) { 40 | 41 | class Builder(c: Context) { 42 | 43 | fun title(title: String) = this 44 | fun title(title: Int) = this 45 | fun text(text: String) = this 46 | fun text(text: Int) = this 47 | fun buttonKill(text: String) = this 48 | fun buttonKill(text: Int) = this 49 | fun buttonCancel(text: String) = this 50 | fun buttonCancel(text: Int) = this 51 | fun icon(icon: Int) = this 52 | fun color(color: Int) = this 53 | 54 | fun build() = NotificationConfig("", "", "", "", 0, 0) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /venom/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright 2020 Yaroslav Berezanskyi 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | apply plugin: 'com.android.library' 26 | apply plugin: 'kotlin-android' 27 | apply from: '../static-analysis.gradle' 28 | apply from: '../common-android.gradle' 29 | 30 | android { 31 | namespace 'com.github.venom' 32 | testNamespace 'com.github.venom.test' 33 | } 34 | 35 | dependencies { 36 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 37 | implementation "androidx.core:core-ktx:$androidXCoreVersion" 38 | testImplementation "junit:junit:$junitVersion" 39 | testImplementation "io.mockk:mockk:$mockkVersion" 40 | androidTestImplementation "androidx.test:rules:$androidXTestRulesVersion" 41 | androidTestImplementation "androidx.test:runner:$androidXTestVersion" 42 | androidTestImplementation "androidx.test.ext:junit:$androidXTestExtVersion" 43 | androidTestImplementation "androidx.test.uiautomator:uiautomator:$uiAutomatorVersion" 44 | } 45 | 46 | project.afterEvaluate { 47 | publishing { 48 | publications { 49 | release(MavenPublication) { 50 | from components.release 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /venom/src/main/java/com/github/venom/service/NotificationConfig.kt: -------------------------------------------------------------------------------- 1 | package com.github.venom.service 2 | 3 | import android.content.Context 4 | import androidx.annotation.ColorRes 5 | import androidx.annotation.DrawableRes 6 | import androidx.annotation.StringRes 7 | import com.github.venom.R 8 | 9 | @Suppress("DataClassPrivateConstructor") 10 | data class NotificationConfig private constructor( 11 | val title: String, 12 | val text: String, 13 | val buttonKill: String, 14 | val buttonRestart: String, 15 | val buttonCancel: String, 16 | val iconRes: Int, 17 | val colorRes: Int 18 | ) { 19 | 20 | class Builder(private val c: Context) { 21 | private var title: String = c.getString(R.string.venom_foreground_service_title) 22 | private var text: String = c.getString(R.string.venom_foreground_service_text) 23 | private var buttonKill: String = c.getString(R.string.venom_notification_button_kill) 24 | private var buttonRestart: String = c.getString(R.string.venom_notification_button_restart) 25 | private var buttonCancel: String = c.getString(R.string.venom_notification_button_cancel) 26 | private var icon: Int = R.drawable.android_adb 27 | private var color: Int = R.color.venom_primary 28 | 29 | fun title(title: String) = apply { this.title = title } 30 | fun title(@StringRes title: Int) = apply { this.title = c.getString(title) } 31 | fun text(text: String) = apply { this.text = text } 32 | fun text(@StringRes text: Int) = apply { this.text = c.getString(text) } 33 | fun buttonKill(text: String) = apply { buttonKill = text } 34 | fun buttonKill(@StringRes text: Int) = apply { buttonKill = c.getString(text) } 35 | fun buttonRestart(text: String) = apply { buttonRestart = text } 36 | fun buttonRestart(@StringRes text: Int) = apply { buttonRestart = c.getString(text) } 37 | fun buttonCancel(text: String) = apply { buttonCancel = text } 38 | fun buttonCancel(@StringRes text: Int) = apply { buttonCancel = c.getString(text) } 39 | fun icon(@DrawableRes icon: Int) = apply { this.icon = icon } 40 | fun color(@ColorRes color: Int) = apply { this.color = color } 41 | 42 | fun build() = NotificationConfig( 43 | title, 44 | text, 45 | buttonKill, 46 | buttonRestart, 47 | buttonCancel, 48 | icon, 49 | color 50 | ) 51 | } 52 | } 53 | 54 | internal fun defaultNotification(c: Context) = NotificationConfig.Builder(c).build() 55 | -------------------------------------------------------------------------------- /venom/src/test/java/com/github/venom/service/ServiceDelegateTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.venom.service 2 | 3 | import android.app.ActivityManager 4 | import android.app.ActivityManager.RunningServiceInfo 5 | import android.content.Context 6 | import android.content.Context.ACTIVITY_SERVICE 7 | import androidx.core.content.ContextCompat 8 | import io.mockk.every 9 | import io.mockk.mockk 10 | import io.mockk.mockkStatic 11 | import io.mockk.verify 12 | import org.junit.Assert.assertFalse 13 | import org.junit.Assert.assertTrue 14 | import org.junit.Before 15 | import org.junit.Test 16 | 17 | class ServiceDelegateTest { 18 | 19 | private val context = mockk(relaxed = true) 20 | 21 | private lateinit var delegate: ServiceDelegate 22 | 23 | @Before 24 | fun setup() { 25 | delegate = ServiceDelegate(context) 26 | } 27 | 28 | @Test 29 | fun startService_startServiceIfNotRunning() { 30 | setRunningState(false) 31 | 32 | mockkStatic(ContextCompat::class) { 33 | delegate.startService() 34 | // it's not possible to verify the Intent unfortunately 35 | verify { ContextCompat.startForegroundService(any(), any()) } 36 | } 37 | } 38 | 39 | @Test 40 | fun startService_dontStartServiceIfAlreadyRunning() { 41 | setRunningState(true) 42 | 43 | mockkStatic(ContextCompat::class) { 44 | delegate.startService() 45 | verify(exactly = 0) { ContextCompat.startForegroundService(any(), any()) } 46 | } 47 | } 48 | 49 | @Test 50 | fun stopService_stopService() { 51 | delegate.stopService() 52 | 53 | verify { context.stopService(any()) } 54 | } 55 | 56 | @Test 57 | fun isServiceRunning_returnTrueIfRunning() { 58 | setRunningState(true) 59 | 60 | assertTrue(delegate.isServiceRunning()) 61 | } 62 | 63 | @Test 64 | fun isServiceRunning_returnFalseIfNotRunning() { 65 | setRunningState(false) 66 | 67 | assertFalse(delegate.isServiceRunning()) 68 | } 69 | 70 | @Suppress("DEPRECATION") 71 | private fun setRunningState(running: Boolean) { 72 | val serviceInfo = mockk() 73 | serviceInfo.service = mockk { 74 | every { className } returns if (running) VenomService::class.java.name else "" 75 | } 76 | every { 77 | context.getSystemService(ACTIVITY_SERVICE) 78 | } returns mockk { 79 | every { getRunningServices(any()) } returns listOf(serviceInfo) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 27 | 28 |