Skip to content

Commit

Permalink
feat: support search custom channel name
Browse files Browse the repository at this point in the history
  • Loading branch information
GSWXXN committed Mar 31, 2023
1 parent 8676930 commit 55340aa
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package com.gswxxn.xmsfnotichannel.activity

import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Intent
import android.net.Uri
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.preference.PreferenceManager
import com.gswxxn.xmsfnotichannel.BuildConfig
import com.gswxxn.xmsfnotichannel.R
import com.gswxxn.xmsfnotichannel.activity.MainActivity.Companion.defaultChannelName
import com.gswxxn.xmsfnotichannel.databinding.ActivityAboutPageBinding
import com.gswxxn.xmsfnotichannel.utils.RoundDegree
import com.gswxxn.xmsfnotichannel.utils.dp2px
Expand All @@ -33,6 +37,46 @@ class AboutPageActivity : BaseActivity() {
)
}, RoundDegree.RoundCorner))

var count = 0
var lastClickTime: Long = 0
appIcon.setOnClickListener {
val now = System.currentTimeMillis()

if (now - lastClickTime < 500) count++
else count = 1

lastClickTime = now

if (count != 5) return@setOnClickListener
count = 0

AlertDialog.Builder(this@AboutPageActivity).apply {
val pref = PreferenceManager.getDefaultSharedPreferences(this@AboutPageActivity)
val input = EditText(this@AboutPageActivity).apply {
setText(pref.getString("search_name", defaultChannelName))
}
setTitle(getString(R.string.searching_name))
setMessage(getString(R.string.searching_name_summary))
setView(input)
setPositiveButton(getString(R.string.alert_ok)) { _, _ ->
if (input.text.toString().isEmpty()) {
Toast.makeText(this@AboutPageActivity, getString(R.string.can_not_be_empty), Toast.LENGTH_SHORT).show()
return@setPositiveButton
}
pref.edit().putString("search_name", input.text.toString()).apply()
}
setNegativeButton(getString(R.string.alert_cancel)) { dialog, _ ->
dialog.cancel()
}
setNeutralButton(getString(R.string.alert_reset)) { _, _ ->
pref.edit().putString("search_name", defaultChannelName).apply()
}
}.create().apply {
setCanceledOnTouchOutside(false)
}.show()

}

miluIcon.setImageBitmap(roundBitmapByShader(
getDrawable(R.mipmap.img_developer)?.let {
drawable2Bitmap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.Toast
import androidx.preference.PreferenceManager
import com.gswxxn.xmsfnotichannel.BuildConfig
import com.gswxxn.xmsfnotichannel.R
import com.gswxxn.xmsfnotichannel.databinding.ActivityMainBinding
Expand All @@ -14,13 +15,17 @@ import com.gswxxn.xmsfnotichannel.utils.AppInfoHelper
import com.gswxxn.xmsfnotichannel.utils.NCUtils
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.dataChannel
import com.highcapable.yukihookapi.hook.factory.hasClass
import kotlinx.coroutines.*

class MainActivity : BaseActivity(), CoroutineScope by MainScope() {

companion object {
const val defaultChannelName = "运营消息"
}

private var androidRestartNeeded = true
private val isMIUI = "android.miui.R".hasClass()
private lateinit var binding: ActivityMainBinding
private var channelName = defaultChannelName

override fun onCreate() {
var appInfoFilter = listOf<AppInfoHelper.MyAppInfo>()
Expand All @@ -40,12 +45,13 @@ class MainActivity : BaseActivity(), CoroutineScope by MainScope() {

// 开始检测
binding.actionButton.setOnClickListener {
if (!isMIUI || androidRestartNeeded) {
if (androidRestartNeeded) {
Toast.makeText(this, getString(R.string.check_active_toast), Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
showView(false, binding.actionButton)
showView(true, binding.configListLoadingView)
appInfo.pattern = channelName
launch {
appInfoFilter = withContext(Dispatchers.Default) { appInfo.getAppInfoList() }

Expand All @@ -57,9 +63,9 @@ class MainActivity : BaseActivity(), CoroutineScope by MainScope() {
// 一键开启
binding.enableAll.setOnClickListener {
appInfoFilter.forEach {
if (it.status == 0) {
nc.enableOperationNotification(it.packageName)
it.status = 3
if (it.ncInfo.importance == 0) {
nc.enableSpecificNotification(it)
it.ncInfo.importance = 3
}
}
onRefreshList?.invoke()
Expand All @@ -68,16 +74,17 @@ class MainActivity : BaseActivity(), CoroutineScope by MainScope() {
// 一键关闭
binding.disableAll.setOnClickListener {
appInfoFilter.forEach {
if (it.status > 0) {
nc.disableOperationNotification(it.packageName)
it.status = 0
if (it.ncInfo.importance > 0) {
nc.disableSpecificNotification(it)
it.ncInfo.importance = 0
}
}
onRefreshList?.invoke()
}

// 重新检测
binding.recheck.setOnClickListener {
appInfo.pattern = channelName
launch {
showView(false, binding.configListView, binding.afterActions)
showView(true, binding.configListLoadingView)
Expand All @@ -92,6 +99,7 @@ class MainActivity : BaseActivity(), CoroutineScope by MainScope() {
// 列表
binding.configListView.apply {
adapter = object : BaseAdapter() {

override fun getCount() = appInfoFilter.size

override fun getItem(position: Int) = appInfoFilter[position]
Expand All @@ -109,44 +117,59 @@ class MainActivity : BaseActivity(), CoroutineScope by MainScope() {
holder = cView?.tag as AdapterConfigBinding
}
getItem(position).also {
val openHint: String
val closeHint: String
if (channelName == defaultChannelName) {
holder.adpChannelInfo.visibility = View.GONE
openHint = getString(R.string.enabled_operation_notification)
closeHint = getString(R.string.disabled_operation_notification)
} else {
holder.adpChannelInfo.visibility = View.VISIBLE
openHint = getString(R.string.enabled_notification_other)
closeHint = getString(R.string.disabled_notification_other)
}

// 设置图标
holder.adpAppIcon.setImageDrawable(it.icon)
// 设置应用名
holder.adpAppName.text = it.appName
// 设置组名
holder.adpChannelGroup.text = it.ncInfo.channelGroupName.let { name -> if (name == "") getString(R.string.no_group) else name }
// 设置通道名
holder.adpChannelName.text = it.ncInfo.channelName
// 设置状态
holder.adpAppStatus.apply {
text = getString(when (it.status) {
-1 -> R.string.did_not_sent_operation_notification
0 -> R.string.disabled_operation_notification
else -> R.string.enabled_operation_notification
})
text = when (it.ncInfo.importance) {
0 -> closeHint
else -> openHint
}
setTextColor(getColor(
when (it.status) {
when (it.ncInfo.importance) {
-1 -> R.color.colorTextGray
0 -> R.color.green
else -> R.color.colorTextRed
0 -> R.color.colorTextRed
else -> R.color.green
}
))
}
// 设置LinearLayout
holder.adapterLayout.setOnClickListener { _ ->
when (it.status) {
when (it.ncInfo.importance) {
-1 -> return@setOnClickListener
0 -> {
nc.enableOperationNotification(it.packageName)
nc.enableSpecificNotification(it)
holder.adpAppStatus.apply {
text = getString(R.string.enabled_operation_notification)
setTextColor(getColor(R.color.colorTextRed))
text = openHint
setTextColor(getColor(R.color.green))
}
it.status = 3
it.ncInfo.importance = 3
}
else -> {
nc.disableOperationNotification(it.packageName)
nc.disableSpecificNotification(it)
holder.adpAppStatus.apply {
text = getString(R.string.disabled_operation_notification)
setTextColor(getColor(R.color.green))
text = closeHint
setTextColor(getColor(R.color.colorTextRed))
}
it.status = 0
it.ncInfo.importance = 0
}
}
}
Expand All @@ -161,20 +184,19 @@ class MainActivity : BaseActivity(), CoroutineScope by MainScope() {

binding.mainStatus.setBackgroundResource(
when {
YukiHookAPI.Status.isXposedModuleActive && (!isMIUI || androidRestartNeeded) -> R.drawable.bg_yellow_round
YukiHookAPI.Status.isXposedModuleActive && androidRestartNeeded -> R.drawable.bg_yellow_round
YukiHookAPI.Status.isXposedModuleActive -> R.drawable.bg_green_round
else -> R.drawable.bg_dark_round
}
)
binding.mainImgStatus.setImageResource(
when {
YukiHookAPI.Status.isXposedModuleActive && isMIUI && !androidRestartNeeded -> R.drawable.ic_success
YukiHookAPI.Status.isXposedModuleActive && !androidRestartNeeded -> R.drawable.ic_success
else -> R.drawable.ic_warn
}
)
binding.mainTextStatus.text = getString(
when {
!isMIUI -> R.string.only_miui
YukiHookAPI.Status.isXposedModuleActive && androidRestartNeeded -> R.string.try_reboot
YukiHookAPI.Status.isXposedModuleActive -> R.string.module_is_active
else -> R.string.module_is_not_active
Expand All @@ -187,7 +209,7 @@ class MainActivity : BaseActivity(), CoroutineScope by MainScope() {

window.statusBarColor = getColor(
when {
YukiHookAPI.Status.isXposedModuleActive && (!isMIUI || androidRestartNeeded) -> R.color.yellow
YukiHookAPI.Status.isXposedModuleActive && androidRestartNeeded -> R.color.yellow
YukiHookAPI.Status.isXposedModuleActive -> R.color.green
else -> R.color.gray
}
Expand All @@ -202,5 +224,6 @@ class MainActivity : BaseActivity(), CoroutineScope by MainScope() {
refreshState()
}
dataChannel("android").put("${BuildConfig.APPLICATION_ID}_send")
channelName = PreferenceManager.getDefaultSharedPreferences(this).getString("search_name", defaultChannelName).toString()
}
}
33 changes: 19 additions & 14 deletions app/src/main/java/com/gswxxn/xmsfnotichannel/utils/AppInfoHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,27 @@ import android.graphics.drawable.Drawable

class AppInfoHelper(private val context : Context) {
private lateinit var appInfoList: MutableList<MyAppInfo>
var pattern: String = ""

data class MyAppInfo(
val appName: String,
val packageName: String,
val icon: Drawable,
var status: Int,
var ncInfo: NCInfo,
val isSystemApp: Boolean
)

data class NCInfo(
val channelGroupName: String,
val channelName: String,
var importance: Int
)

fun getAppInfoList(): MutableList<MyAppInfo> {
if (::appInfoList.isInitialized)
return appInfoList.apply {
sortBy { it.appName }
sortByDescending {it.status }
sortByDescending {it.ncInfo.importance }
}.toMutableList()
return getAppInfoListForNew()
}
Expand All @@ -29,21 +36,19 @@ class AppInfoHelper(private val context : Context) {
val pm = context.packageManager
val ncUtils = NCUtils(context)
for (appInfo in pm.getInstalledApplications(0)) {
MyAppInfo(
appInfo.loadLabel(pm).toString(),
appInfo.packageName,
appInfo.loadIcon(pm),
ncUtils.getNotificationChannelImportance(appInfo.packageName, "运营消息"),
appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0
).also { appInfoList.add(it) }
ncUtils.getNotificationChannelInfoByRegex(appInfo.packageName, pattern).forEach {
appInfoList.add(MyAppInfo(
appInfo.loadLabel(pm).toString(),
appInfo.packageName,
appInfo.loadIcon(pm),
it,
appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0
))
}
}
return appInfoList.apply {
sortBy { it.appName }
sortByDescending { it.status }
sortByDescending { it.ncInfo.importance }
}.toMutableList()
}

fun setStatus(info : MyAppInfo, status : Int) {
appInfoList[appInfoList.indexOf(info)].status = status
}
}
40 changes: 22 additions & 18 deletions app/src/main/java/com/gswxxn/xmsfnotichannel/utils/NCUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,6 @@ class NCUtils(private val context : Context) {
Int::class.java,
NotificationChannel::class.java) as Method

private fun setOperationNotification(pkgName: String, importance: Int) {
getNotificationChannelGroups(pkgName).forEach { group ->
group.channels.forEach { channel ->
if (channel.name == "运营消息") {
channel.importance = importance
setNotificationChannel(pkgName, channel)
}
}
}
}

private fun getNotificationChannelGroups(pkgName: String) =
notificationChannelGroupsM.invoke(sINM, pkgName, context.packageManager.getPackageUid(pkgName, 0), false).let {
Class.forName("android.content.pm.ParceledListSlice").getDeclaredMethod("getList")
Expand All @@ -54,18 +43,33 @@ class NCUtils(private val context : Context) {
sINM, pkgName, context.packageManager.getPackageUid(pkgName, 0), channel
)

fun getNotificationChannelImportance(pkgName: String, channelName: String): Int {
// 获取通知通道信息
fun getNotificationChannelInfoByRegex(pkgName: String, channelNameRegex: String): List<AppInfoHelper.NCInfo> {
val ncInfoList = mutableListOf<AppInfoHelper.NCInfo>()
getNotificationChannelGroups(pkgName).forEach{ notificationChannelGroup ->
notificationChannelGroup.channels.forEach {
if (it.name == channelName) return it.importance
if (it.name.matches(Regex(channelNameRegex)))
ncInfoList.add(AppInfoHelper.NCInfo(notificationChannelGroup.name.toString(), it.name.toString(), it.importance))
}
}
return -1
return ncInfoList
}

fun disableOperationNotification(pkgName: String) =
setOperationNotification(pkgName, NotificationManager.IMPORTANCE_NONE)
fun enableSpecificNotification(appInfo: AppInfoHelper.MyAppInfo) {
getNotificationChannelGroups(appInfo.packageName).forEach { group ->
group.channels.forEach { channel ->
channel.importance = NotificationManager.IMPORTANCE_DEFAULT
setNotificationChannel(appInfo.packageName, channel)
}
}
}

fun enableOperationNotification(pkgName: String) =
setOperationNotification(pkgName, NotificationManager.IMPORTANCE_DEFAULT)
fun disableSpecificNotification(appInfo: AppInfoHelper.MyAppInfo) {
getNotificationChannelGroups(appInfo.packageName).forEach { group ->
group.channels.forEach { channel ->
channel.importance = NotificationManager.IMPORTANCE_NONE
setNotificationChannel(appInfo.packageName, channel)
}
}
}
}
Loading

0 comments on commit 55340aa

Please sign in to comment.