浏览代码

Added permanent notification

Vadik Sirekanyan 2 年之前
父节点
当前提交
4636ae7232

+ 2 - 1
app/build.gradle

@@ -1,5 +1,5 @@
 apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
+apply plugin: 'org.jetbrains.kotlin.android'
 apply plugin: 'org.sirekanyan.version-checker'
 
 android {
@@ -19,6 +19,7 @@ android {
         release {
             minifyEnabled false
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
+            signingConfig debug.signingConfig
         }
     }
     compileOptions {

+ 1 - 0
app/grant.sh

@@ -17,6 +17,7 @@ DEVICES=$("$ADB_EXECUTABLE" devices | grep device | grep -v devices | cut -f1)
 for device in ${DEVICES}; do
   grant WRITE_SECURE_SETTINGS
   grant SET_ALWAYS_FINISH
+  grant POST_NOTIFICATIONS
 done
 
 exit 0

+ 13 - 11
app/src/main/AndroidManifest.xml

@@ -1,18 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="ProtectedPermissions">
 
-    <uses-permission
-        android:name="android.permission.WRITE_SETTINGS"
-        tools:ignore="ProtectedPermissions" />
-    <uses-permission
-        android:name="android.permission.WRITE_SECURE_SETTINGS"
-        tools:ignore="ProtectedPermissions" />
-    <uses-permission
-        android:name="android.permission.SET_ALWAYS_FINISH"
-        tools:ignore="ProtectedPermissions" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
+    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
 
     <application
+        android:name=".App"
         android:allowBackup="false"
         android:dataExtractionRules="@xml/data_extraction_rules"
         android:fullBackupContent="false"
@@ -25,13 +22,18 @@
 
         <activity
             android:name=".MainActivity"
-            android:exported="true">
+            android:exported="true"
+            android:launchMode="singleTop">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
 
+        <receiver
+            android:name=".ResetReceiver"
+            android:exported="false" />
+
     </application>
 
 </manifest>

+ 11 - 0
app/src/main/kotlin/org/sirekanyan/devtools/App.kt

@@ -0,0 +1,11 @@
+package org.sirekanyan.devtools
+
+import android.app.Application
+import android.content.Context
+
+val Context.app: App
+    get() = applicationContext as App
+
+class App : Application() {
+    val notifications by lazy { Notifications(this) }
+}

+ 9 - 9
app/src/main/kotlin/org/sirekanyan/devtools/MainActivity.kt

@@ -9,6 +9,7 @@ import kotlin.reflect.KMutableProperty0
 class MainActivity : AppCompatActivity() {
 
     private val settings by lazy { Settings(contentResolver) }
+    private val notifications by lazy { app.notifications }
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -18,11 +19,13 @@ class MainActivity : AppCompatActivity() {
                     orientation = LinearLayout.VERTICAL
                     addLinear {
                         addText("dev") {
-                            init(adb = 1, font = 1.15f, screen = 120)
+                            notifications.show()
+                            settings.init(adb = 1, font = 1.15f, screen = 120)
                             recreate()
                         }
                         addText("reset") {
-                            init(adb = 0, font = 1.0f, screen = 30)
+                            notifications.hide()
+                            settings.init()
                             finish()
                         }
                         onLongClick {
@@ -36,13 +39,9 @@ class MainActivity : AppCompatActivity() {
                 }
             }
         )
-    }
-
-    private fun init(adb: Int, font: Float, screen: Long) {
-        settings.adb = adb
-        settings.dka = 0
-        settings.font = font
-        settings.screen = screen
+        if (savedInstanceState == null) {
+            notifications.show()
+        }
     }
 
     private fun <T> LinearLayout.addSwitcher(property: KMutableProperty0<T>, vararg values: T) {
@@ -52,6 +51,7 @@ class MainActivity : AppCompatActivity() {
             values.forEach { value ->
                 val text = "${property.name} $value"
                 addText(if (value == currentValue) "[$text]" else text) {
+                    notifications.show()
                     property.set(value)
                     recreate()
                 }

+ 59 - 0
app/src/main/kotlin/org/sirekanyan/devtools/Notifications.kt

@@ -0,0 +1,59 @@
+package org.sirekanyan.devtools
+
+import android.Manifest.permission.POST_NOTIFICATIONS
+import android.app.Application
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.PendingIntent
+import android.app.PendingIntent.FLAG_IMMUTABLE
+import android.content.Intent
+import android.content.pm.PackageManager.PERMISSION_GRANTED
+import android.os.Build
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import androidx.core.content.ContextCompat
+
+private const val CHANNEL_NAME = "Main Channel"
+private const val CHANNEL_ID = "main_channel"
+private const val NOTIFICATION_ID = 2304
+
+class Notifications(private val context: Application) {
+
+    private val manager: NotificationManagerCompat =
+        NotificationManagerCompat.from(context).also {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                val channel = NotificationChannel(CHANNEL_ID, CHANNEL_NAME, IMPORTANCE_DEFAULT)
+                it.createNotificationChannel(channel)
+            }
+        }
+
+    private val notification: Notification =
+        NotificationCompat.Builder(context, CHANNEL_ID)
+            .setSmallIcon(R.drawable.baseline_build_24)
+            .setContentTitle("Development is active")
+            .setContentText("Swipe to deactivate")
+            .setContentIntent(
+                Intent(context, MainActivity::class.java).let { intent ->
+                    PendingIntent.getActivity(context, 8797, intent, FLAG_IMMUTABLE)
+                }
+            )
+            .setDeleteIntent(
+                Intent(context, ResetReceiver::class.java).let { intent ->
+                    PendingIntent.getBroadcast(context, 3609, intent, FLAG_IMMUTABLE)
+                }
+            )
+            .setSilent(true)
+            .build()
+
+    fun show() {
+        if (ContextCompat.checkSelfPermission(context, POST_NOTIFICATIONS) == PERMISSION_GRANTED) {
+            manager.notify(NOTIFICATION_ID, notification)
+        }
+    }
+
+    fun hide() {
+        manager.cancel(NOTIFICATION_ID)
+    }
+
+}

+ 16 - 0
app/src/main/kotlin/org/sirekanyan/devtools/ResetReceiver.kt

@@ -0,0 +1,16 @@
+package org.sirekanyan.devtools
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+
+class ResetReceiver : BroadcastReceiver() {
+    override fun onReceive(context: Context, intent: Intent) {
+        try {
+            Settings(context.contentResolver).init()
+        } catch (exception: Exception) {
+            Notifications(context.app).show()
+            throw exception
+        }
+    }
+}

+ 7 - 0
app/src/main/kotlin/org/sirekanyan/devtools/Settings.kt

@@ -12,4 +12,11 @@ class Settings(val resolver: ContentResolver) {
     var screen: Long by SystemSetting(System.SCREEN_OFF_TIMEOUT, multiplier = 1000)
     var rotation: Int by SystemSetting(System.USER_ROTATION)
 
+    fun init(adb: Int = 0, font: Float = 1.0f, screen: Long = 30) {
+        this.adb = adb
+        this.dka = 0
+        this.font = font
+        this.screen = screen
+    }
+
 }

+ 5 - 0
app/src/main/res/drawable/baseline_build_24.xml

@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#000000"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#ffffffff" android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z"/>
+</vector>