From a002e9c9e73d0950a6b2c76ca34bd299a43e6a5e Mon Sep 17 00:00:00 2001
From: Maary <24504742+Steve-Mr@users.noreply.github.com>
Date: Thu, 2 May 2024 18:20:13 +0800
Subject: [PATCH 1/2] target sdk 34
---
app/build.gradle | 4 +-
app/src/main/AndroidManifest.xml | 5 +-
.../java/com/maary/liveinpeace/Constants.kt | 3 +
.../liveinpeace/service/QSTileService.kt | 168 +++++++++++++-----
.../res/drawable/outline_battery_saver_24.xml | 5 +
.../outline_notifications_active_24.xml | 5 +
app/src/main/res/layout/item_connection.xml | 16 +-
app/src/main/res/values/strings.xml | 6 +
build.gradle | 4 +-
gradle/wrapper/gradle-wrapper.properties | 2 +-
10 files changed, 161 insertions(+), 57 deletions(-)
create mode 100644 app/src/main/res/drawable/outline_battery_saver_24.xml
create mode 100644 app/src/main/res/drawable/outline_notifications_active_24.xml
diff --git a/app/build.gradle b/app/build.gradle
index 3287150..131a3bd 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -12,12 +12,12 @@ keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
namespace 'com.maary.liveinpeace'
- compileSdk 33
+ compileSdk 34
defaultConfig {
applicationId "com.maary.liveinpeace"
minSdk 31
- targetSdk 33
+ targetSdk 34
versionCode 4
versionName "2.1_beta"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5233a50..b9f10f1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,6 +5,8 @@
+
+
+ android:exported="false"
+ android:foregroundServiceType="specialUse">
diff --git a/app/src/main/java/com/maary/liveinpeace/Constants.kt b/app/src/main/java/com/maary/liveinpeace/Constants.kt
index 2c5079b..0974f07 100644
--- a/app/src/main/java/com/maary/liveinpeace/Constants.kt
+++ b/app/src/main/java/com/maary/liveinpeace/Constants.kt
@@ -15,12 +15,14 @@ class Constants {
const val PREF_NOTIFY_TEXT_SIZE = "notification_text_size"
const val PREF_WATCHING_CONNECTING_TIME = "watching_connecting"
const val PREF_ENABLE_EAR_PROTECTION = "ear_protection_enabled"
+ const val PREF_WELCOME_FINISHED = "welcome_finished"
// 设置通知 id
const val ID_NOTIFICATION_SETTINGS = 3
// 前台通知 id
const val ID_NOTIFICATION_FOREGROUND = 1
const val ID_NOTIFICATION_ALERT = 2
const val ID_NOTIFICATION_PROTECT = 4
+ const val ID_NOTIFICATION_WELCOME = 0
// 设置图像式图标 Action
const val ACTION_NAME_SET_IMG = "com.maary.liveinpeace.receiver.SettingsReceiver.SetIconImg"
// 设置字符式图标 Action
@@ -45,6 +47,7 @@ class Constants {
const val CHANNEL_ID_SETTINGS = "LIP_SETTINGS"
const val CHANNEL_ID_ALERT = "LIP_ALERT"
const val CHANNEL_ID_PROTECT = "LIP_PROTECT"
+ const val CHANNEL_ID_WELCOME = "LIP_WELCOME"
// 提醒时间
const val ALERT_TIME: Long = 2*60*60*1000
// 延后时间
diff --git a/app/src/main/java/com/maary/liveinpeace/service/QSTileService.kt b/app/src/main/java/com/maary/liveinpeace/service/QSTileService.kt
index 478944c..7fe9171 100644
--- a/app/src/main/java/com/maary/liveinpeace/service/QSTileService.kt
+++ b/app/src/main/java/com/maary/liveinpeace/service/QSTileService.kt
@@ -1,28 +1,41 @@
package com.maary.liveinpeace.service
import android.Manifest
+import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
+import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.graphics.drawable.Icon
+import android.net.Uri
import android.os.Build
+import android.os.PowerManager
import android.provider.Settings
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
+import androidx.core.app.NotificationCompat
+import androidx.core.content.edit
+import com.maary.liveinpeace.Constants
import com.maary.liveinpeace.Constants.Companion.BROADCAST_ACTION_FOREGROUND
import com.maary.liveinpeace.Constants.Companion.BROADCAST_FOREGROUND_INTENT_EXTRA
import com.maary.liveinpeace.Constants.Companion.CHANNEL_ID_ALERT
import com.maary.liveinpeace.Constants.Companion.CHANNEL_ID_DEFAULT
import com.maary.liveinpeace.Constants.Companion.CHANNEL_ID_PROTECT
import com.maary.liveinpeace.Constants.Companion.CHANNEL_ID_SETTINGS
+import com.maary.liveinpeace.Constants.Companion.CHANNEL_ID_WELCOME
+import com.maary.liveinpeace.Constants.Companion.ID_NOTIFICATION_GROUP_SETTINGS
+import com.maary.liveinpeace.Constants.Companion.ID_NOTIFICATION_SETTINGS
+import com.maary.liveinpeace.Constants.Companion.ID_NOTIFICATION_WELCOME
+import com.maary.liveinpeace.Constants.Companion.PREF_WELCOME_FINISHED
import com.maary.liveinpeace.Constants.Companion.REQUESTING_WAIT_MILLIS
+import com.maary.liveinpeace.Constants.Companion.SHARED_PREF
import com.maary.liveinpeace.R
class QSTileService: TileService() {
@@ -33,6 +46,54 @@ class QSTileService: TileService() {
val tile = qsTile
var waitMillis = REQUESTING_WAIT_MILLIS
+ val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ if (notificationManager.getNotificationChannel(CHANNEL_ID_DEFAULT) == null){
+ createNotificationChannel(
+ NotificationManager.IMPORTANCE_MIN,
+ CHANNEL_ID_DEFAULT,
+ resources.getString(R.string.default_channel),
+ resources.getString(R.string.default_channel_description)
+ )
+ }
+ if (notificationManager.getNotificationChannel(CHANNEL_ID_SETTINGS) == null) {
+ createNotificationChannel(
+ NotificationManager.IMPORTANCE_MIN,
+ CHANNEL_ID_SETTINGS,
+ resources.getString(R.string.channel_settings),
+ resources.getString(R.string.settings_channel_description)
+ )
+ }
+ if (notificationManager.getNotificationChannel(CHANNEL_ID_ALERT) == null) {
+ createNotificationChannel(
+ NotificationManager.IMPORTANCE_HIGH,
+ CHANNEL_ID_ALERT,
+ resources.getString(R.string.channel_alert),
+ resources.getString(R.string.alert_channel_description)
+ )
+ }
+ if (notificationManager.getNotificationChannel(CHANNEL_ID_PROTECT) == null) {
+ val channel = NotificationChannel(
+ CHANNEL_ID_PROTECT,
+ resources.getString(R.string.channel_protection),
+ NotificationManager.IMPORTANCE_LOW).apply {
+ description = resources.getString(R.string.protection_channel_description)
+ enableVibration(false)
+ setSound(null, null)
+ }
+ // Register the channel with the system
+ notificationManager.createNotificationChannel(channel)
+ }
+ if (notificationManager.getNotificationChannel(CHANNEL_ID_WELCOME) == null){
+ createNotificationChannel(
+ NotificationManager.IMPORTANCE_MIN,
+ CHANNEL_ID_WELCOME,
+ resources.getString(R.string.welcome_channel),
+ resources.getString(R.string.welcome_channel_description)
+ )
+ }
+
+ val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
+
while(ActivityCompat.checkSelfPermission(
applicationContext,
Manifest.permission.POST_NOTIFICATIONS
@@ -44,49 +105,27 @@ class QSTileService: TileService() {
waitMillis *= 2
}
+ val sharedPref = getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE)
+ while (!sharedPref.getBoolean(PREF_WELCOME_FINISHED, false)){
+ if ( powerManager.isIgnoringBatteryOptimizations(packageName) &&
+ ActivityCompat.checkSelfPermission(
+ applicationContext, Manifest.permission.POST_NOTIFICATIONS
+ ) == PackageManager.PERMISSION_GRANTED) {
+ sharedPref.edit {
+ putBoolean(PREF_WELCOME_FINISHED, true)
+ }
+ break
+ } else {
+ createWelcomeNotification()
+ Thread.sleep(waitMillis.toLong())
+ waitMillis *= 2
+ }
+ }
+
val intent = Intent(this, ForegroundService::class.java)
if (!ForegroundService.isForegroundServiceRunning()){
-
- val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- if (notificationManager.getNotificationChannel(CHANNEL_ID_DEFAULT) == null){
- createNotificationChannel(
- NotificationManager.IMPORTANCE_MIN,
- CHANNEL_ID_DEFAULT,
- resources.getString(R.string.default_channel),
- resources.getString(R.string.default_channel_description)
- )
- }
- if (notificationManager.getNotificationChannel(CHANNEL_ID_SETTINGS) == null) {
- createNotificationChannel(
- NotificationManager.IMPORTANCE_MIN,
- CHANNEL_ID_SETTINGS,
- resources.getString(R.string.channel_settings),
- resources.getString(R.string.settings_channel_description)
- )
- }
- if (notificationManager.getNotificationChannel(CHANNEL_ID_ALERT) == null) {
- createNotificationChannel(
- NotificationManager.IMPORTANCE_HIGH,
- CHANNEL_ID_ALERT,
- resources.getString(R.string.channel_alert),
- resources.getString(R.string.alert_channel_description)
- )
- }
- if (notificationManager.getNotificationChannel(CHANNEL_ID_PROTECT) == null) {
- val channel = NotificationChannel(
- CHANNEL_ID_PROTECT,
- resources.getString(R.string.channel_protection),
- NotificationManager.IMPORTANCE_LOW).apply {
- description = resources.getString(R.string.protection_channel_description)
- enableVibration(false)
- setSound(null, null)
- }
- // Register the channel with the system
- notificationManager.createNotificationChannel(channel)
- }
-
applicationContext.startForegroundService(intent)
tile.state = Tile.STATE_ACTIVE
tile.icon = Icon.createWithResource(this, R.drawable.icon_qs_one)
@@ -101,11 +140,12 @@ class QSTileService: TileService() {
tile.updateTile()
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
override fun onStartListening() {
super.onStartListening()
val intentFilter = IntentFilter()
intentFilter.addAction(BROADCAST_ACTION_FOREGROUND)
- registerReceiver(foregroundServiceReceiver, intentFilter)
+ registerReceiver(foregroundServiceReceiver, intentFilter, RECEIVER_NOT_EXPORTED)
}
override fun onStopListening() {
@@ -149,8 +189,48 @@ class QSTileService: TileService() {
notificationManager.createNotificationChannel(channel)
}
- private fun requestNotificationsPermission() = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
- }.let(::startActivityAndCollapse)
+ private fun requestNotificationsPermission() {
+ val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
+ }
+ val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ startActivityAndCollapse(pendingIntent)
+ }
+ }
+
+ @SuppressLint("BatteryLife")
+ private fun createWelcomeNotification() {
+ Log.v("MUTE_", "CREATING WELCOME")
+ val welcome = NotificationCompat.Builder(this, CHANNEL_ID_WELCOME)
+ .setOngoing(true)
+ .setSmallIcon(R.drawable.ic_baseline_settings_24)
+ .setShowWhen(false)
+ .setContentTitle(getString(R.string.welcome))
+ .setContentText(getString(R.string.welcome_description))
+ .setOnlyAlertOnce(true)
+ .setGroupSummary(false)
+ .setGroup(ID_NOTIFICATION_GROUP_SETTINGS)
+
+ val batteryIntent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
+ batteryIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .data = Uri.parse("package:$packageName")
+
+ val pendingBatteryIntent = PendingIntent.getActivity(this, 0, batteryIntent, PendingIntent.FLAG_IMMUTABLE)
+
+ val batteryAction = NotificationCompat.Action.Builder(
+ R.drawable.outline_battery_saver_24,
+ getString(R.string.request_permission_battery),
+ pendingBatteryIntent
+ ).build()
+
+ welcome.addAction(batteryAction)
+
+ val notificationManager: NotificationManager =
+ getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+
+ notificationManager.notify(ID_NOTIFICATION_WELCOME, welcome.build())
+
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/outline_battery_saver_24.xml b/app/src/main/res/drawable/outline_battery_saver_24.xml
new file mode 100644
index 0000000..ed790ee
--- /dev/null
+++ b/app/src/main/res/drawable/outline_battery_saver_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/outline_notifications_active_24.xml b/app/src/main/res/drawable/outline_notifications_active_24.xml
new file mode 100644
index 0000000..32611df
--- /dev/null
+++ b/app/src/main/res/drawable/outline_notifications_active_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_connection.xml b/app/src/main/res/layout/item_connection.xml
index e0ece23..8bdc59d 100644
--- a/app/src/main/res/layout/item_connection.xml
+++ b/app/src/main/res/layout/item_connection.xml
@@ -11,23 +11,25 @@
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toTopOf="@id/device_name"
+ app:layout_constraintBottom_toBottomOf="@id/device_connection_time"
android:contentDescription="@string/icon_of_device"
tools:src="@drawable/ic_headphone"
/>
+ android:layout_marginEnd="16dp"
+ android:maxLines="2"
+ tools:text="HeadphoneHeadphoneHeadphoneHeadphoneHeadphone"/>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 28eedd9..8b5b861 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -35,6 +35,12 @@
Ears Protected
Protecting ears
Auto adjust volume below 25 when connecting to a new device.
+ Initial Settings
+ Permission settings for first time use.
+ Welcome
+ LiveInPeace needs permissions to work.
+ Battery
+ Notification
- Shhhhhhh…
- Perfectly Balanced, As All Things Should Be…
diff --git a/build.gradle b/build.gradle
index 115194f..8d7c329 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id 'com.android.application' version '8.0.2' apply false
- id 'com.android.library' version '8.0.2' apply false
+ id 'com.android.application' version '8.3.1' apply false
+ id 'com.android.library' version '8.3.1' apply false
id 'org.jetbrains.kotlin.android' version '1.9.0-Beta' apply false
}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index dd4d381..7a55c6d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Fri May 12 10:24:55 CST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
From 4b0d04675e205534b8777e729d1a9419af1f8204 Mon Sep 17 00:00:00 2001
From: Maary <24504742+Steve-Mr@users.noreply.github.com>
Date: Thu, 2 May 2024 18:28:29 +0800
Subject: [PATCH 2/2] =?UTF-8?q?=E4=B8=AD=E6=96=87=20string?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/src/main/res/values-zh-rCN/strings.xml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index ca862f1..2fe72c7 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -43,4 +43,10 @@
保护了耳朵
保护耳朵
有新设备连接时自动将音量调节至 25 以下
+ 初始设置
+ 初次使用权限设置
+ 欢迎
+ LiveInPeace 需要这些权限
+ 电池
+ 通知
\ No newline at end of file