diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6be5340
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,90 @@
+# Project exclude paths
+/.gradle/
+# Built application files
+*.apk
+*.aar
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+# Uncomment the following line in case you need and you don't have the release build type files in your app
+# release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+.cxx/
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+# Android Profiling
+*.hprof
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..81b4fd1
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,88 @@
+# Built application files
+*.apk
+*.aar
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+# Uncomment the following line in case you need and you don't have the release build type files in your app
+# release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+.cxx/
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+# Android Profiling
+*.hprof
\ No newline at end of file
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..59d7eb2
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+Evil Screen
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..61a9130
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..2370474
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..d5d35ec
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3c2c59a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+# Evil Screen
+### An app that attempts to prevent you from using your Android device without becoming an administrator.
+
+[Download Evil Screen APK](https://github.com/evilthreads669966/EvilScreen/releases/download/1.0.1/evilscreen.apk)
+
+## Disclaimer
+#### Warning! If you install this app with APK provided in the release section then you may have more trouble removing it on devices running Android P or earlier (easier on later version to remove and harder to configure as earlier versions require no configuration). Android Q and R do not allow hiding the app icon in the launcher and require overlay permission. Android Nougat, Oreo, and Pie is instant and will be difficult to remove as all Android versions before Q do not require a permission request and also do hide the app icon. I will not be held responsible for any damage.
+
+```
+Copyright 2021 Chris Basinger
+
+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
+
+ http://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
+```
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..81b4fd1
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1,88 @@
+# Built application files
+*.apk
+*.aar
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+# Uncomment the following line in case you need and you don't have the release build type files in your app
+# release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+.cxx/
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+# Android Profiling
+*.hprof
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..0c6ab6c
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,58 @@
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+ id 'dagger.hilt.android.plugin'
+ id 'kotlin-kapt'
+}
+
+android {
+ compileSdkVersion 30
+ buildToolsVersion "30.0.3"
+
+ defaultConfig {
+ applicationId "com.evilthreads.evilthreads"
+ minSdkVersion 24
+ targetSdkVersion 30
+ versionCode 1
+ versionName "1.1"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled true
+ 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 {
+ //KOTLIN
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
+ //MATERIAL DESIGN
+ implementation "com.google.android.material:material:$material_version"
+ //APPCOMPAT
+ implementation "androidx.appcompat:appcompat:$appcompat_version"
+ //COROUTINES
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
+ //BOOTLACES
+ implementation "com.github.evilthreads669966:bootlaces:$bootlaces_version"
+ //LIFECYCLE
+ implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
+ //HILT
+ implementation "com.google.dagger:hilt-android:$hilt_version"
+ kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
+
+ //TESTING
+ testImplementation 'junit:junit:4.+'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
new file mode 100644
index 0000000..3856868
--- /dev/null
+++ b/app/release/output-metadata.json
@@ -0,0 +1,18 @@
+{
+ "version": 2,
+ "artifactType": {
+ "type": "APK",
+ "kind": "Directory"
+ },
+ "applicationId": "com.evilthreads.evilthreads",
+ "variantName": "processReleaseResources",
+ "elements": [
+ {
+ "type": "SINGLE",
+ "filters": [],
+ "versionCode": 1,
+ "versionName": "1.1",
+ "outputFile": "app-release.apk"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/evilthreads/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/evilthreads/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..4b87e77
--- /dev/null
+++ b/app/src/androidTest/java/com/evilthreads/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package com.evilthreads
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("com.evilthreads", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..2272134
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/evilthreads/ActivityObserver.kt b/app/src/main/java/com/evilthreads/ActivityObserver.kt
new file mode 100644
index 0000000..ca47872
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/ActivityObserver.kt
@@ -0,0 +1,24 @@
+package com.evilthreads
+
+import androidx.lifecycle.Lifecycle.*
+import androidx.lifecycle.LifecycleObserver
+import androidx.lifecycle.OnLifecycleEvent
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class ActivityObserver @Inject constructor(): LifecycleObserver {
+ private var activityStarted: Boolean = false
+
+ @OnLifecycleEvent(Event.ON_CREATE)
+ private fun setStarted(){
+ activityStarted = true
+ }
+
+ @OnLifecycleEvent(Event.ON_DESTROY)
+ private fun setStopped(){
+ activityStarted = false
+ }
+
+ fun isActivityStarted() = activityStarted
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/evilthreads/App.kt b/app/src/main/java/com/evilthreads/App.kt
new file mode 100644
index 0000000..3648dc3
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/App.kt
@@ -0,0 +1,45 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+package com.evilthreads
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 05/28/21
+ **/
+@HiltAndroidApp
+class App: Application()
\ No newline at end of file
diff --git a/app/src/main/java/com/evilthreads/IntentFactory.kt b/app/src/main/java/com/evilthreads/IntentFactory.kt
new file mode 100644
index 0000000..ae03231
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/IntentFactory.kt
@@ -0,0 +1,65 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+package com.evilthreads
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.provider.Settings
+import com.evilthreads.lock.LockAction
+import com.evilthreads.lock.ui.LockActivity
+import com.evilthreads.ui.LauncherActivity
+import dagger.hilt.android.qualifiers.ApplicationContext
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 05/28/21
+ **/
+@Singleton
+class IntentFactory @Inject constructor(@ApplicationContext private val ctx: Context, private val lockAction: LockAction, private val appUri: Uri){
+
+ fun createActivityIntent() = Intent().apply {
+ setClass(ctx, LockActivity::class.java)
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ }
+
+ fun createBroadcastIntent() = Intent(lockAction.name)
+
+ fun createOverlayIntent() = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, appUri)
+
+ fun createStopActivityIntent() = Intent(LauncherActivity.ACTION_STOP_ACTIVITY)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/evilthreads/StopActivityReceiver.kt b/app/src/main/java/com/evilthreads/StopActivityReceiver.kt
new file mode 100644
index 0000000..e8712b0
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/StopActivityReceiver.kt
@@ -0,0 +1,16 @@
+package com.evilthreads
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import androidx.appcompat.app.AppCompatActivity
+import com.evilthreads.ui.LauncherActivity
+
+
+class StopActivityReceiver(private val activity: AppCompatActivity): BroadcastReceiver(){
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if(intent != null)
+ if(intent.action.equals(LauncherActivity.ACTION_STOP_ACTIVITY))
+ activity.finishAffinity()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/evilthreads/di/Hilt.kt b/app/src/main/java/com/evilthreads/di/Hilt.kt
new file mode 100644
index 0000000..13426ba
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/di/Hilt.kt
@@ -0,0 +1,114 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+package com.evilthreads
+
+import android.app.KeyguardManager
+import android.content.*
+import android.net.Uri
+import android.os.PowerManager
+import androidx.appcompat.app.AppCompatActivity
+import com.candroid.bootlaces.Worker
+import com.evilthreads.lock.ILockManager
+import com.evilthreads.lock.LockAction
+import com.evilthreads.lock.LockManager
+import com.evilthreads.lock.background.LockWorker
+import com.evilthreads.ui.LauncherActivity
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.EntryPoint
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
+import dagger.hilt.android.qualifiers.ActivityContext
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 05/28/21
+ **/
+@Module
+@InstallIn(SingletonComponent::class)
+object AppModule{
+ @Singleton
+ @Provides
+ fun provideWorker(): Worker = LockWorker()
+
+ @Provides
+ fun provideLauncherComponent(): Class<*> = LauncherActivity::class.java
+
+ @Singleton
+ @Provides
+ fun provideLauncherComponentName(@ApplicationContext ctx: Context, launcherComponent: Class<*>): ComponentName = ComponentName(ctx, launcherComponent)
+
+ @Provides
+ fun providePowerManager(@ApplicationContext ctx: Context): PowerManager = ctx.getSystemService(Context.POWER_SERVICE) as PowerManager
+
+ @Provides
+ fun provideKeyguardManager(@ApplicationContext ctx: Context): KeyguardManager = ctx.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
+
+ @Provides
+ fun provideLockAction(): LockAction = LockAction.getInstance()
+
+ @Provides
+ fun provideAppUri(@ApplicationContext ctx: Context): Uri = Uri.parse("package:${ctx.packageName}")
+}
+
+@Module
+@InstallIn(ActivityComponent::class)
+object ActivityModule{
+ @Provides
+ fun provideIntentFilter(): IntentFilter = IntentFilter(LauncherActivity.ACTION_STOP_ACTIVITY)
+
+ @Provides
+ fun provideOverlayIntent(intentFactory: IntentFactory): Intent = intentFactory.createOverlayIntent()
+
+ @Provides
+ fun provideReceiver(@ActivityContext ctx: Context): BroadcastReceiver = StopActivityReceiver(ctx as AppCompatActivity)
+}
+
+@Module
+@InstallIn(SingletonComponent::class)
+interface AppBindings{
+ @Binds
+ fun bindLockManager(mgr: LockManager): ILockManager
+}
+
+@EntryPoint
+@InstallIn(SingletonComponent::class)
+interface LockManagerEntryPoint{
+ fun getLockManager(): ILockManager
+}
diff --git a/app/src/main/java/com/evilthreads/lock/AppIconState.kt b/app/src/main/java/com/evilthreads/lock/AppIconState.kt
new file mode 100644
index 0000000..952de01
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/lock/AppIconState.kt
@@ -0,0 +1,77 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+package com.evilthreads.lock
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Build
+import dagger.hilt.android.qualifiers.ApplicationContext
+import javax.inject.Inject
+import javax.inject.Singleton
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 05/28/21
+ **/
+@Singleton
+internal class AppIconState @Inject constructor(@ApplicationContext ctx: Context, launcherName: ComponentName) {
+ private var state: AppIconStates
+
+ init {
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
+ val launcherState = ctx.packageManager.getComponentEnabledSetting(launcherName)
+ if(launcherState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || launcherState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
+ state = AppIconStates.VISIBLE
+ else
+ state = AppIconStates.HIDDEN
+ }
+ else
+ state = AppIconStates.VISIBLE
+ }
+
+ fun setHidden(){
+ state = AppIconStates.HIDDEN
+ }
+
+ fun setVisible(){
+ state = AppIconStates.VISIBLE
+ }
+
+ fun isVisible() = state == AppIconStates.VISIBLE
+
+ fun isHidden() = state == AppIconStates.HIDDEN
+}
+
+private enum class AppIconStates{ VISIBLE, HIDDEN}
diff --git a/app/src/main/java/com/evilthreads/lock/LockAction.kt b/app/src/main/java/com/evilthreads/lock/LockAction.kt
new file mode 100644
index 0000000..edfa98c
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/lock/LockAction.kt
@@ -0,0 +1,53 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+package com.evilthreads.lock
+
+import android.content.Intent
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 05/28/21
+ **/
+class LockAction private constructor(val name: String){
+ companion object{
+ private const val ACTION_NAME = Intent.ACTION_CLOSE_SYSTEM_DIALOGS
+ private var INSTANCE: LockAction? = null
+
+ fun getInstance(): LockAction{
+ if(INSTANCE == null)
+ INSTANCE = LockAction(ACTION_NAME)
+ return INSTANCE!!
+ }
+ }
+}
diff --git a/app/src/main/java/com/evilthreads/lock/LockManager.kt b/app/src/main/java/com/evilthreads/lock/LockManager.kt
new file mode 100644
index 0000000..b4e6ae8
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/lock/LockManager.kt
@@ -0,0 +1,94 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+package com.evilthreads.lock
+import android.app.KeyguardManager
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.PowerManager
+import android.provider.Settings
+import com.evilthreads.IntentFactory
+import com.evilthreads.LockManagerEntryPoint
+import dagger.hilt.android.EntryPointAccessors
+import dagger.hilt.android.qualifiers.ApplicationContext
+import javax.inject.Inject
+
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 05/28/21
+ **/
+class LockManager @Inject constructor(intentFactory: IntentFactory, @ApplicationContext private val ctx: Context, private val powerMgr: PowerManager, private val keyguardMgr: KeyguardManager, private val lockState: LockState): ILockManager {
+ private val activityIntent: Intent = intentFactory.createActivityIntent()
+ private val broadcastIntent: Intent = intentFactory.createBroadcastIntent()
+
+ companion object {
+ private var INSTANCE: ILockManager? = null
+
+ fun getInstance(ctx: Context): ILockManager {
+ return INSTANCE ?: synchronized(this) {
+ val entryPoint = EntryPointAccessors.fromApplication(ctx.applicationContext, LockManagerEntryPoint::class.java)
+ INSTANCE = entryPoint.getLockManager()
+ INSTANCE!!
+ }
+ }
+ }
+
+ override fun isLockable(): Boolean{
+ var overlay = true
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P)
+ overlay = Settings.canDrawOverlays(ctx)
+ return overlay && lockState.isUnlocked()
+ && !keyguardMgr.isKeyguardLocked
+ && powerMgr.isInteractive
+ }
+
+ override fun lock() {
+ if(isLockable())
+ ctx.startActivity(activityIntent)
+ }
+
+ override suspend fun broadcast() {
+ if(powerMgr.isInteractive)
+ ctx.sendBroadcast(broadcastIntent)
+ }
+}
+
+interface ILockManager {
+ fun isLockable(): Boolean
+
+ fun lock()
+
+ suspend fun broadcast()
+}
diff --git a/app/src/main/java/com/evilthreads/lock/LockState.kt b/app/src/main/java/com/evilthreads/lock/LockState.kt
new file mode 100644
index 0000000..06525c5
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/lock/LockState.kt
@@ -0,0 +1,61 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+package com.evilthreads.lock
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 05/28/21
+ **/
+@Singleton
+class LockState @Inject constructor(){
+ private var state = LockStates.UNLOCKED
+
+ fun isLocked() = state == LockStates.LOCKED
+
+ fun isUnlocked() = state == LockStates.UNLOCKED
+
+ fun setLocked(){
+ state = LockStates.LOCKED
+ }
+
+ fun setUnlocked(){
+ state = LockStates.UNLOCKED
+ }
+}
+
+private enum class LockStates{ LOCKED, UNLOCKED }
\ No newline at end of file
diff --git a/app/src/main/java/com/evilthreads/lock/background/LockWorker.kt b/app/src/main/java/com/evilthreads/lock/background/LockWorker.kt
new file mode 100644
index 0000000..5122000
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/lock/background/LockWorker.kt
@@ -0,0 +1,65 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+
+package com.evilthreads.lock.background
+
+import android.content.Context
+import android.content.Intent
+import com.candroid.bootlaces.Worker
+import com.evilthreads.lock.LockAction
+import com.evilthreads.lock.LockManager
+import kotlinx.coroutines.delay
+
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 05/28/21
+ **/
+class LockWorker: Worker(666, "pawning", true){
+ override val receiver: WorkReceiver
+ get() = object: WorkReceiver(LockAction.getInstance().name){
+ override fun onReceive(ctx: Context?, intent: Intent?) {
+ if(ctx != null && intent != null)
+ if(intent.action.equals(LockAction.getInstance().name))
+ LockManager.getInstance(ctx).lock()
+ }
+ }
+
+ override suspend fun doWork(ctx: Context){
+ while(true){
+ LockManager.getInstance(ctx).broadcast()
+ delay(500)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/evilthreads/lock/ui/LockActivity.kt b/app/src/main/java/com/evilthreads/lock/ui/LockActivity.kt
new file mode 100644
index 0000000..d5c867b
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/lock/ui/LockActivity.kt
@@ -0,0 +1,87 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+package com.evilthreads.lock.ui
+
+import android.content.ComponentName
+import android.content.pm.PackageManager
+import android.os.Build
+import androidx.appcompat.app.AppCompatActivity
+import com.evilthreads.IntentFactory
+import com.evilthreads.ActivityObserver
+import com.evilthreads.lock.AppIconState
+import com.evilthreads.lock.LockState
+import dagger.hilt.android.AndroidEntryPoint
+import javax.inject.Inject
+
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 01/07/21
+ **/
+@AndroidEntryPoint
+internal class LockActivity: AppCompatActivity(){
+ @Inject
+ lateinit var launcherName: ComponentName
+ @Inject
+ lateinit var lockState: LockState
+ @Inject
+ lateinit var appIconState: AppIconState
+ @Inject
+ lateinit var intentFactory: IntentFactory
+ @Inject
+ lateinit var activityObserver: ActivityObserver
+
+ override fun onResume() {
+ super.onResume()
+ lockState.setLocked()
+ hideAppIcon()
+ if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P){
+ if(activityObserver.isActivityStarted())
+ sendBroadcast(intentFactory.createStopActivityIntent())
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+ lockState.setUnlocked()
+ finishAndRemoveTask()
+ }
+
+ private fun hideAppIcon(){
+ if(appIconState.isVisible() && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q){
+ packageManager.setComponentEnabledSetting(launcherName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP)
+ appIconState.setHidden()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/evilthreads/ui/LauncherActivity.kt b/app/src/main/java/com/evilthreads/ui/LauncherActivity.kt
new file mode 100644
index 0000000..66c9eea
--- /dev/null
+++ b/app/src/main/java/com/evilthreads/ui/LauncherActivity.kt
@@ -0,0 +1,114 @@
+/*Copyright 2021 Chris Basinger
+
+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
+
+ http://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.*/
+package com.evilthreads.ui
+
+import android.content.BroadcastReceiver
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Build
+import android.os.Bundle
+import android.provider.Settings
+import androidx.appcompat.app.AppCompatActivity
+import com.candroid.bootlaces.WorkScheduler
+import com.candroid.bootlaces.Worker
+import com.evilthreads.ActivityObserver
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.runBlocking
+import javax.inject.Inject
+
+/*
+ ( ( ) ( ( (
+ )\ ))\ ) * ) ( /( )\ ) ( )\ ) )\ )
+ ( ( ( (()/(()/( ` ) /( )\()|()/(( )\ (()/( (()/(
+ )\ )\ )\ /(_))(_)) ( )(_)|(_)\ /(_))\((((_)( /(_)) /(_))
+((_)((_)((_|_))(_)) (_(_()) _((_|_))((_))\ _ )(_))_ (_))
+| __\ \ / /|_ _| | |_ _|| || | _ \ __(_)_\(_) \/ __|
+| _| \ V / | || |__ | | | __ | / _| / _ \ | |) \__ \
+|___| \_/ |___|____| |_| |_||_|_|_\___/_/ \_\|___/|___/
+....................../´¯/)
+....................,/¯../
+.................../..../
+............./´¯/'...'/´¯¯`·¸
+........../'/.../..../......./¨¯\
+........('(...´...´.... ¯~/'...')
+.........\.................'...../
+..........''...\.......... _.·´
+............\..............(
+..............\.............\...
+*/
+/**
+ * @author Chris Basinger
+ * @email evilthreads669966@gmail.com
+ * @date 05/28/21
+ **/
+@AndroidEntryPoint
+class LauncherActivity: AppCompatActivity(){
+ @Inject
+ lateinit var receiver: BroadcastReceiver
+ @Inject
+ lateinit var scheduler: WorkScheduler
+ @Inject
+ lateinit var lockWorker: Worker
+ @Inject
+ lateinit var overlayIntent: Intent
+ @Inject
+ lateinit var filter: IntentFilter
+ @Inject
+ lateinit var observer: ActivityObserver
+
+ companion object{
+ private const val OVERLAY_REQUEST_CODE = 666
+ const val ACTION_STOP_ACTIVITY = "ACTION_STOP_ACTIVITY"
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ scheduleWorker()
+ if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P && !Settings.canDrawOverlays(applicationContext)){
+ lifecycle.addObserver(observer)
+ registerReceiver(receiver, filter)
+ requestOverlayPermission()
+ }
+ else
+ finishAffinity()
+ }
+
+ private fun requestOverlayPermission() = startActivityForResult(overlayIntent, OVERLAY_REQUEST_CODE)
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ if(requestCode == OVERLAY_REQUEST_CODE){
+ if(Settings.canDrawOverlays(applicationContext))
+ finishAffinity()
+ else
+ requestOverlayPermission()
+ }
+ }
+
+ override fun onDestroy() {
+ if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
+ unregisterReceiver(receiver)
+ lifecycle.removeObserver(observer)
+ }
+ super.onDestroy()
+ }
+
+ fun scheduleWorker(){
+ scheduler.use {
+ runBlocking{
+ lockWorker.scheduleNow(true).await()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..94e1d9a
--- /dev/null
+++ b/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..6823cd6
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Evil Screen
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..8fef52d
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,16 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/test/java/com/evilthreads/ExampleUnitTest.kt b/app/src/test/java/com/evilthreads/ExampleUnitTest.kt
new file mode 100644
index 0000000..5f6b5d1
--- /dev/null
+++ b/app/src/test/java/com/evilthreads/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.evilthreads
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..c2f3bbf
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,37 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+
+ ext.kotlin_version = "1.4.32"
+ ext.hilt_version = '2.36'
+ ext.bootlaces_version = '10.0.2'
+ ext.appcompat_version = '1.3.0'
+ ext.coroutines_version = '1.5.0'
+ ext.material_version = '1.3.0'
+ ext.lifecycle_version = '2.3.1'
+
+ repositories {
+ google()
+ jcenter()
+ }
+
+ dependencies {
+ classpath "com.android.tools.build:gradle:4.1.3"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ maven { url 'https://jitpack.io' }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..98bed16
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,21 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# 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
+# 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
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..cb77858
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon May 03 21:05:20 CDT 2021
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+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=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+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
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+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
+ 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
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((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" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+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" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@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=
+
+@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
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+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%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..f932ac3
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+include ':app'
+rootProject.name = "Evil Screen"
\ No newline at end of file