Trim SystemUI rendering infrastructure
This commit is contained in:
@@ -29,11 +29,7 @@ internal class AospLockscreenBackend(
|
|||||||
private lateinit var calculateShelfIcons: Method
|
private lateinit var calculateShelfIcons: Method
|
||||||
private lateinit var shelfNotification: Field
|
private lateinit var shelfNotification: Field
|
||||||
private lateinit var shelfIconStates: Field
|
private lateinit var shelfIconStates: Field
|
||||||
private lateinit var shelfClampedAmount: Field
|
private lateinit var iconState: IconStateAccess
|
||||||
private lateinit var shelfAppearAmount: Field
|
|
||||||
private lateinit var shelfAlpha: Field
|
|
||||||
private lateinit var shelfHidden: Field
|
|
||||||
private lateinit var shelfVisibleState: Field
|
|
||||||
@Volatile private var blockedObserved = false
|
@Volatile private var blockedObserved = false
|
||||||
|
|
||||||
override fun install(classLoader: ClassLoader): Boolean {
|
override fun install(classLoader: ClassLoader): Boolean {
|
||||||
@@ -108,13 +104,13 @@ internal class AospLockscreenBackend(
|
|||||||
val entryMethod = rowClass.methods.firstOrNull { it.name == "getEntry" && it.parameterCount == 0 }
|
val entryMethod = rowClass.methods.firstOrNull { it.name == "getEntry" && it.parameterCount == 0 }
|
||||||
val entryField = findField(rowClass, "mEntry", "entry")
|
val entryField = findField(rowClass, "mEntry", "entry")
|
||||||
require(entryMethod != null || entryField != null) { "AOSP notification row entry is unavailable" }
|
require(entryMethod != null || entryField != null) { "AOSP notification row entry is unavailable" }
|
||||||
entryForRow = accessor(entryMethod, entryField)
|
entryForRow = memberAccessor(entryMethod, entryField)
|
||||||
|
|
||||||
val entryClass = entryMethod?.returnType ?: entryField!!.type
|
val entryClass = entryMethod?.returnType ?: entryField!!.type
|
||||||
val sbnMethod = entryClass.methods.firstOrNull { it.name == "getSbn" && it.parameterCount == 0 }
|
val sbnMethod = entryClass.methods.firstOrNull { it.name == "getSbn" && it.parameterCount == 0 }
|
||||||
val sbnField = findField(entryClass, "mSbn", "sbn", "mStatusBarNotification")
|
val sbnField = findField(entryClass, "mSbn", "sbn", "mStatusBarNotification")
|
||||||
require(sbnMethod != null || sbnField != null) { "AOSP notification entry SBN is unavailable" }
|
require(sbnMethod != null || sbnField != null) { "AOSP notification entry SBN is unavailable" }
|
||||||
val accessor = accessor(sbnMethod, sbnField)
|
val accessor = memberAccessor(sbnMethod, sbnField)
|
||||||
sbnForEntry = { accessor(it) as? StatusBarNotification }
|
sbnForEntry = { accessor(it) as? StatusBarNotification }
|
||||||
val attachedChildren = rowClass.methods.firstOrNull {
|
val attachedChildren = rowClass.methods.firstOrNull {
|
||||||
it.name == "getAttachedChildren" && it.parameterCount == 0
|
it.name == "getAttachedChildren" && it.parameterCount == 0
|
||||||
@@ -139,17 +135,12 @@ internal class AospLockscreenBackend(
|
|||||||
private fun installShelfFilter(classLoader: ClassLoader) {
|
private fun installShelfFilter(classLoader: ClassLoader) {
|
||||||
val iconContainer = Class.forName(ICON_CONTAINER, false, classLoader)
|
val iconContainer = Class.forName(ICON_CONTAINER, false, classLoader)
|
||||||
val iconView = Class.forName(STATUS_BAR_ICON_VIEW, false, classLoader)
|
val iconView = Class.forName(STATUS_BAR_ICON_VIEW, false, classLoader)
|
||||||
val iconState = Class.forName(ICON_STATE, false, classLoader)
|
iconState = IconStateAccess(Class.forName(ICON_STATE, false, classLoader))
|
||||||
calculateShelfIcons = iconContainer.declaredMethods.singleOrNull {
|
calculateShelfIcons = iconContainer.declaredMethods.singleOrNull {
|
||||||
it.name == "calculateIconXTranslations" && it.parameterCount == 0
|
it.name == "calculateIconXTranslations" && it.parameterCount == 0
|
||||||
}?.also { it.isAccessible = true } ?: error("AOSP shelf icon layout method not found")
|
}?.also { it.isAccessible = true } ?: error("AOSP shelf icon layout method not found")
|
||||||
shelfNotification = requireField(iconView, "mNotification")
|
shelfNotification = requireField(iconView, "mNotification")
|
||||||
shelfIconStates = requireField(iconContainer, "mIconStates")
|
shelfIconStates = requireField(iconContainer, "mIconStates")
|
||||||
shelfClampedAmount = requireField(iconState, "clampedAppearAmount")
|
|
||||||
shelfAppearAmount = requireField(iconState, "iconAppearAmount")
|
|
||||||
shelfAlpha = requireField(iconState, "mAlpha")
|
|
||||||
shelfHidden = requireField(iconState, "hidden")
|
|
||||||
shelfVisibleState = requireField(iconState, "visibleState")
|
|
||||||
|
|
||||||
framework.hook(calculateShelfIcons).intercept { chain ->
|
framework.hook(calculateShelfIcons).intercept { chain ->
|
||||||
val container = chain.thisObject as? ViewGroup
|
val container = chain.thisObject as? ViewGroup
|
||||||
@@ -161,14 +152,14 @@ internal class AospLockscreenBackend(
|
|||||||
val states = shelfIconStates.get(container) as? Map<*, *>
|
val states = shelfIconStates.get(container) as? Map<*, *>
|
||||||
?: return@intercept chain.proceed()
|
?: return@intercept chain.proceed()
|
||||||
val blocked = children.filter(::isBlockedShelfIcon)
|
val blocked = children.filter(::isBlockedShelfIcon)
|
||||||
blocked.forEach { states[it]?.let(::hideShelfIconState) }
|
blocked.forEach { states[it]?.let(iconState::hide) }
|
||||||
children.filterNot(blocked::contains).forEach(container::bringChildToFront)
|
children.filterNot(blocked::contains).forEach(container::bringChildToFront)
|
||||||
val result = try {
|
val result = try {
|
||||||
chain.proceed()
|
chain.proceed()
|
||||||
} finally {
|
} finally {
|
||||||
children.forEach(container::bringChildToFront)
|
children.forEach(container::bringChildToFront)
|
||||||
}
|
}
|
||||||
blocked.forEach { states[it]?.let(::hideShelfIconState) }
|
blocked.forEach { states[it]?.let(iconState::hide) }
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -245,14 +236,6 @@ internal class AospLockscreenBackend(
|
|||||||
return runCatching { onKeyguard.invoke(stack) as Boolean }.getOrDefault(false)
|
return runCatching { onKeyguard.invoke(stack) as Boolean }.getOrDefault(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideShelfIconState(state: Any) {
|
|
||||||
shelfClampedAmount.setFloat(state, 0f)
|
|
||||||
shelfAppearAmount.setFloat(state, 0f)
|
|
||||||
shelfAlpha.setFloat(state, 0f)
|
|
||||||
shelfHidden.setBoolean(state, true)
|
|
||||||
shelfVisibleState.setInt(state, ICON_HIDDEN)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hideRow(row: View) {
|
private fun hideRow(row: View) {
|
||||||
if (row.visibility == View.GONE && row.alpha == 0f) return
|
if (row.visibility == View.GONE && row.alpha == 0f) return
|
||||||
hiddenRows.putIfAbsent(row, RowState(row.visibility, row.alpha))
|
hiddenRows.putIfAbsent(row, RowState(row.visibility, row.alpha))
|
||||||
@@ -281,29 +264,6 @@ internal class AospLockscreenBackend(
|
|||||||
setGroupCount(row, current.size)
|
setGroupCount(row, current.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun accessor(method: Method?, field: Field?): (Any) -> Any? {
|
|
||||||
method?.isAccessible = true
|
|
||||||
field?.isAccessible = true
|
|
||||||
return if (method != null) ({ target -> method.invoke(target) }) else ({ target -> field!!.get(target) })
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findField(type: Class<*>, vararg names: String): Field? {
|
|
||||||
var current: Class<*>? = type
|
|
||||||
while (current != null) {
|
|
||||||
names.forEach { name ->
|
|
||||||
runCatching { current.getDeclaredField(name) }.getOrNull()?.let {
|
|
||||||
it.isAccessible = true
|
|
||||||
return it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current = current.superclass
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requireField(type: Class<*>, name: String) =
|
|
||||||
findField(type, name) ?: error("AOSP $name field is unavailable")
|
|
||||||
|
|
||||||
private data class RowState(val visibility: Int, val alpha: Float)
|
private data class RowState(val visibility: Int, val alpha: Float)
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
@@ -314,6 +274,5 @@ internal class AospLockscreenBackend(
|
|||||||
const val ICON_CONTAINER = "com.android.systemui.statusbar.phone.NotificationIconContainer"
|
const val ICON_CONTAINER = "com.android.systemui.statusbar.phone.NotificationIconContainer"
|
||||||
const val ICON_STATE = "$ICON_CONTAINER\$IconState"
|
const val ICON_STATE = "$ICON_CONTAINER\$IconState"
|
||||||
const val STATUS_BAR_ICON_VIEW = "com.android.systemui.statusbar.StatusBarIconView"
|
const val STATUS_BAR_ICON_VIEW = "com.android.systemui.statusbar.StatusBarIconView"
|
||||||
const val ICON_HIDDEN = 2
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,13 +37,11 @@ internal class OneUiCardsGridRenderer {
|
|||||||
suspend(container, false)
|
suspend(container, false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
state.active = active
|
state.active = true
|
||||||
state.visibleCardKeys = visibleCardKeys
|
state.visibleCardKeys = visibleCardKeys
|
||||||
state.config = config
|
state.config = config
|
||||||
if (active) {
|
val native = if (config.hideShelf) findNativeSurface(container) else container
|
||||||
val native = if (config.hideShelf) findNativeSurface(container) else container
|
if (native !== container.rootView) hideNative(state, native)
|
||||||
if (native !== container.rootView) hideNative(state, native)
|
|
||||||
}
|
|
||||||
scheduleRender(container, state)
|
scheduleRender(container, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-48
@@ -8,7 +8,6 @@ import android.view.ViewGroup
|
|||||||
import io.github.libxposed.api.XposedInterface
|
import io.github.libxposed.api.XposedInterface
|
||||||
import se.ajpanton.notificationsmaster.visibility.NotificationSurface
|
import se.ajpanton.notificationsmaster.visibility.NotificationSurface
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
import java.lang.reflect.Method
|
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.WeakHashMap
|
import java.util.WeakHashMap
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
@@ -24,11 +23,7 @@ internal class OneUiLockscreenCardsBackend(
|
|||||||
private lateinit var sbnForEntry: (Any) -> StatusBarNotification?
|
private lateinit var sbnForEntry: (Any) -> StatusBarNotification?
|
||||||
private lateinit var shelfNotification: Field
|
private lateinit var shelfNotification: Field
|
||||||
private lateinit var shelfIconStates: Field
|
private lateinit var shelfIconStates: Field
|
||||||
private lateinit var shelfClampedAmount: Field
|
private lateinit var iconState: IconStateAccess
|
||||||
private lateinit var shelfAppearAmount: Field
|
|
||||||
private lateinit var shelfAlpha: Field
|
|
||||||
private lateinit var shelfHidden: Field
|
|
||||||
private lateinit var shelfVisibleState: Field
|
|
||||||
@Volatile private var statusBarStateKnown = false
|
@Volatile private var statusBarStateKnown = false
|
||||||
@Volatile private var statusBarState = SHADE
|
@Volatile private var statusBarState = SHADE
|
||||||
@Volatile private var dozing = false
|
@Volatile private var dozing = false
|
||||||
@@ -117,13 +112,13 @@ internal class OneUiLockscreenCardsBackend(
|
|||||||
val entryMethod = rowClass.methods.firstOrNull { it.name == "getEntry" && it.parameterCount == 0 }
|
val entryMethod = rowClass.methods.firstOrNull { it.name == "getEntry" && it.parameterCount == 0 }
|
||||||
val entryField = findField(rowClass, "mEntry", "entry")
|
val entryField = findField(rowClass, "mEntry", "entry")
|
||||||
require(entryMethod != null || entryField != null) { "OneUI notification row entry is unavailable" }
|
require(entryMethod != null || entryField != null) { "OneUI notification row entry is unavailable" }
|
||||||
entryForRow = accessor(entryMethod, entryField)
|
entryForRow = memberAccessor(entryMethod, entryField)
|
||||||
|
|
||||||
val entryClass = entryMethod?.returnType ?: entryField!!.type
|
val entryClass = entryMethod?.returnType ?: entryField!!.type
|
||||||
val sbnMethod = entryClass.methods.firstOrNull { it.name == "getSbn" && it.parameterCount == 0 }
|
val sbnMethod = entryClass.methods.firstOrNull { it.name == "getSbn" && it.parameterCount == 0 }
|
||||||
val sbnField = findField(entryClass, "mSbn", "sbn", "mStatusBarNotification")
|
val sbnField = findField(entryClass, "mSbn", "sbn", "mStatusBarNotification")
|
||||||
require(sbnMethod != null || sbnField != null) { "OneUI notification entry SBN is unavailable" }
|
require(sbnMethod != null || sbnField != null) { "OneUI notification entry SBN is unavailable" }
|
||||||
val accessor = accessor(sbnMethod, sbnField)
|
val accessor = memberAccessor(sbnMethod, sbnField)
|
||||||
sbnForEntry = { accessor(it) as? StatusBarNotification }
|
sbnForEntry = { accessor(it) as? StatusBarNotification }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,12 +131,7 @@ internal class OneUiLockscreenCardsBackend(
|
|||||||
}
|
}
|
||||||
shelfIconStates = findField(shelfIcons, "mIconStates")
|
shelfIconStates = findField(shelfIcons, "mIconStates")
|
||||||
?: error("OneUI shelf icon states are unavailable")
|
?: error("OneUI shelf icon states are unavailable")
|
||||||
val iconState = Class.forName(ICON_STATE, false, classLoader)
|
iconState = IconStateAccess(Class.forName(ICON_STATE, false, classLoader))
|
||||||
shelfClampedAmount = requireField(iconState, "clampedAppearAmount")
|
|
||||||
shelfAppearAmount = requireField(iconState, "iconAppearAmount")
|
|
||||||
shelfAlpha = requireField(iconState, "mAlpha")
|
|
||||||
shelfHidden = requireField(iconState, "hidden")
|
|
||||||
shelfVisibleState = requireField(iconState, "visibleState")
|
|
||||||
val calculate = shelfIcons.declaredMethods.singleOrNull {
|
val calculate = shelfIcons.declaredMethods.singleOrNull {
|
||||||
it.name == "calculateIconXTranslations" && it.parameterCount == 0
|
it.name == "calculateIconXTranslations" && it.parameterCount == 0
|
||||||
} ?: error("OneUI shelf icon layout method not found")
|
} ?: error("OneUI shelf icon layout method not found")
|
||||||
@@ -156,7 +146,7 @@ internal class OneUiLockscreenCardsBackend(
|
|||||||
val states = shelfIconStates.get(container) as? Map<*, *>
|
val states = shelfIconStates.get(container) as? Map<*, *>
|
||||||
?: return@intercept chain.proceed()
|
?: return@intercept chain.proceed()
|
||||||
val blocked = children.filter(::isBlockedShelfIcon)
|
val blocked = children.filter(::isBlockedShelfIcon)
|
||||||
blocked.forEach { icon -> states[icon]?.let(::hideShelfIconState) }
|
blocked.forEach { icon -> states[icon]?.let(iconState::hide) }
|
||||||
children.filterNot(blocked::contains).forEach(container::bringChildToFront)
|
children.filterNot(blocked::contains).forEach(container::bringChildToFront)
|
||||||
val result = try {
|
val result = try {
|
||||||
chain.proceed()
|
chain.proceed()
|
||||||
@@ -165,7 +155,7 @@ internal class OneUiLockscreenCardsBackend(
|
|||||||
}
|
}
|
||||||
// OneUI applies these states after this calculation returns. Suppress every
|
// OneUI applies these states after this calculation returns. Suppress every
|
||||||
// stock shelf icon in Cards mode; the renderer owns the supplemental grid.
|
// stock shelf icon in Cards mode; the renderer owns the supplemental grid.
|
||||||
children.forEach { icon -> states[icon]?.let(::hideShelfIconState) }
|
children.forEach { icon -> states[icon]?.let(iconState::hide) }
|
||||||
if (!nativeShelfSuppressedObserved) {
|
if (!nativeShelfSuppressedObserved) {
|
||||||
nativeShelfSuppressedObserved = true
|
nativeShelfSuppressedObserved = true
|
||||||
Log.i(TAG, "Suppressed the native OneUI Cards shelf icon states")
|
Log.i(TAG, "Suppressed the native OneUI Cards shelf icon states")
|
||||||
@@ -216,12 +206,6 @@ internal class OneUiLockscreenCardsBackend(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun accessor(method: Method?, field: Field?): (Any) -> Any? {
|
|
||||||
method?.isAccessible = true
|
|
||||||
field?.isAccessible = true
|
|
||||||
return if (method != null) ({ target -> method.invoke(target) }) else ({ target -> field!!.get(target) })
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateState(controller: Any) {
|
private fun updateState(controller: Any) {
|
||||||
(findField(controller.javaClass, "mState")?.get(controller) as? Int)?.let {
|
(findField(controller.javaClass, "mState")?.get(controller) as? Int)?.let {
|
||||||
statusBarState = it
|
statusBarState = it
|
||||||
@@ -297,14 +281,6 @@ internal class OneUiLockscreenCardsBackend(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideShelfIconState(state: Any) {
|
|
||||||
shelfClampedAmount.setFloat(state, 0f)
|
|
||||||
shelfAppearAmount.setFloat(state, 0f)
|
|
||||||
shelfAlpha.setFloat(state, 0f)
|
|
||||||
shelfHidden.setBoolean(state, true)
|
|
||||||
shelfVisibleState.setInt(state, ICON_HIDDEN)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hideRow(row: View) {
|
private fun hideRow(row: View) {
|
||||||
if (row.visibility == View.GONE && row.alpha == 0f) return
|
if (row.visibility == View.GONE && row.alpha == 0f) return
|
||||||
hiddenRows.putIfAbsent(row, RowState(row.visibility, row.alpha))
|
hiddenRows.putIfAbsent(row, RowState(row.visibility, row.alpha))
|
||||||
@@ -350,23 +326,6 @@ internal class OneUiLockscreenCardsBackend(
|
|||||||
private fun booleanField(target: Any, name: String) =
|
private fun booleanField(target: Any, name: String) =
|
||||||
runCatching { findField(target.javaClass, name)?.getBoolean(target) ?: false }.getOrDefault(false)
|
runCatching { findField(target.javaClass, name)?.getBoolean(target) ?: false }.getOrDefault(false)
|
||||||
|
|
||||||
private fun requireField(type: Class<*>, name: String) =
|
|
||||||
findField(type, name) ?: error("OneUI $name field is unavailable")
|
|
||||||
|
|
||||||
private fun findField(type: Class<*>, vararg names: String): Field? {
|
|
||||||
var current: Class<*>? = type
|
|
||||||
while (current != null) {
|
|
||||||
names.forEach { name ->
|
|
||||||
runCatching { current.getDeclaredField(name) }.getOrNull()?.let {
|
|
||||||
it.isAccessible = true
|
|
||||||
return it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current = current.superclass
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun gridConfig() = OneUiCardsGridRenderer.Config(
|
private fun gridConfig() = OneUiCardsGridRenderer.Config(
|
||||||
ProcessVisibilityPolicyCache.lockscreenCards,
|
ProcessVisibilityPolicyCache.lockscreenCards,
|
||||||
showPills = true,
|
showPills = true,
|
||||||
@@ -380,7 +339,6 @@ internal class OneUiLockscreenCardsBackend(
|
|||||||
const val SHADE = 0
|
const val SHADE = 0
|
||||||
const val KEYGUARD = 1
|
const val KEYGUARD = 1
|
||||||
const val CARDS = 0
|
const val CARDS = 0
|
||||||
const val ICON_HIDDEN = 2
|
|
||||||
const val LOCKSCREEN_STYLE = "lockscreen_minimizing_notification"
|
const val LOCKSCREEN_STYLE = "lockscreen_minimizing_notification"
|
||||||
const val STACK = "com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout"
|
const val STACK = "com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout"
|
||||||
const val ROW = "com.android.systemui.statusbar.notification.row.ExpandableNotificationRow"
|
const val ROW = "com.android.systemui.statusbar.notification.row.ExpandableNotificationRow"
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import android.view.ViewGroup
|
|||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import io.github.libxposed.api.XposedInterface
|
import io.github.libxposed.api.XposedInterface
|
||||||
import java.lang.reflect.Field
|
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import java.text.NumberFormat
|
import java.text.NumberFormat
|
||||||
import java.util.WeakHashMap
|
import java.util.WeakHashMap
|
||||||
@@ -390,11 +389,7 @@ private data class BatteryState(val level: Int, val plugged: Boolean, val charge
|
|||||||
private fun currentBatteryState(context: Context): BatteryState? {
|
private fun currentBatteryState(context: Context): BatteryState? {
|
||||||
val app = context.applicationContext
|
val app = context.applicationContext
|
||||||
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
|
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
|
||||||
val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
val intent = app.registerReceiver(null, filter, Context.RECEIVER_EXPORTED) ?: return null
|
||||||
app.registerReceiver(null, filter, Context.RECEIVER_EXPORTED)
|
|
||||||
} else {
|
|
||||||
app.registerReceiver(null, filter)
|
|
||||||
} ?: return null
|
|
||||||
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
|
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
|
||||||
val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)
|
val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)
|
||||||
if (level < 0 || scale <= 0) return null
|
if (level < 0 || scale <= 0) return null
|
||||||
@@ -405,31 +400,15 @@ private fun currentBatteryState(context: Context): BatteryState? {
|
|||||||
return BatteryState(percent, plugged, status == BatteryManager.BATTERY_STATUS_FULL || percent >= 100)
|
return BatteryState(percent, plugged, status == BatteryManager.BATTERY_STATUS_FULL || percent >= 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun currentApplicationContext(): Context? = runCatching {
|
|
||||||
Class.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null) as? Context
|
|
||||||
}.getOrNull()
|
|
||||||
|
|
||||||
private fun ClassLoader.findClass(name: String) = runCatching { Class.forName(name, false, this) }.getOrNull()
|
private fun ClassLoader.findClass(name: String) = runCatching { Class.forName(name, false, this) }.getOrNull()
|
||||||
|
|
||||||
private fun Class<*>.methodsNamed(name: String): List<Method> = declaredMethods.filter { it.name == name }.onEach {
|
private fun Class<*>.methodsNamed(name: String): List<Method> = declaredMethods.filter { it.name == name }.onEach {
|
||||||
it.isAccessible = true
|
it.isAccessible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Class<*>.staticField(name: String): Any? = findField(name)?.get(null)
|
private fun Class<*>.staticField(name: String): Any? = findField(this, name)?.get(null)
|
||||||
|
|
||||||
private fun Any?.field(name: String): Any? = this?.javaClass?.findField(name)?.get(this)
|
private fun Any?.field(name: String): Any? = this?.let { findField(it.javaClass, name)?.get(it) }
|
||||||
|
|
||||||
private fun Class<*>.findField(name: String): Field? {
|
|
||||||
var type: Class<*>? = this
|
|
||||||
while (type != null) {
|
|
||||||
runCatching { type.getDeclaredField(name) }.getOrNull()?.let {
|
|
||||||
it.isAccessible = true
|
|
||||||
return it
|
|
||||||
}
|
|
||||||
type = type.superclass
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Any?.invokeNamed(name: String, vararg args: Any?): Any? {
|
private fun Any?.invokeNamed(name: String, vararg args: Any?): Any? {
|
||||||
val target = this ?: return null
|
val target = this ?: return null
|
||||||
|
|||||||
-6
@@ -73,12 +73,6 @@ internal object ProcessVisibilityPolicyCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun currentApplicationContext(): Context? = runCatching {
|
|
||||||
Class.forName("android.app.ActivityThread")
|
|
||||||
.getMethod("currentApplication")
|
|
||||||
.invoke(null) as? Context
|
|
||||||
}.getOrNull()
|
|
||||||
|
|
||||||
private fun retryOrGiveUp() {
|
private fun retryOrGiveUp() {
|
||||||
if (++attempts < MAX_ATTEMPTS) {
|
if (++attempts < MAX_ATTEMPTS) {
|
||||||
Handler(Looper.getMainLooper()).postDelayed(::tryInstall, RETRY_DELAY_MILLIS)
|
Handler(Looper.getMainLooper()).postDelayed(::tryInstall, RETRY_DELAY_MILLIS)
|
||||||
|
|||||||
@@ -170,26 +170,26 @@ internal class SamsungAodBackend(private val framework: XposedInterface) : Visib
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun beginDozeTransition(container: ViewGroup, origin: Pair<Int, Int>) {
|
private fun beginDozeTransition(container: ViewGroup, origin: Pair<Int, Int>) {
|
||||||
val now = SystemClock.uptimeMillis()
|
|
||||||
val current = screenLocation(container)
|
val current = screenLocation(container)
|
||||||
cardsTransitions[container] = CardsTransition(
|
beginTransition(container, origin, current, current != origin)
|
||||||
origin,
|
|
||||||
current,
|
|
||||||
current != origin,
|
|
||||||
now,
|
|
||||||
now + TRANSITION_FALLBACK_DELAY,
|
|
||||||
)
|
|
||||||
cardsRenderer.suspend(container, isCardsMode(container), container)
|
|
||||||
refreshCardsGrid(POSITION_POLL_DELAY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun beginAttachedTransition(container: ViewGroup) {
|
private fun beginAttachedTransition(container: ViewGroup) {
|
||||||
val now = SystemClock.uptimeMillis()
|
|
||||||
val current = screenLocation(container)
|
val current = screenLocation(container)
|
||||||
|
beginTransition(container, current, current, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun beginTransition(
|
||||||
|
container: ViewGroup,
|
||||||
|
origin: Pair<Int, Int>,
|
||||||
|
current: Pair<Int, Int>,
|
||||||
|
moved: Boolean,
|
||||||
|
) {
|
||||||
|
val now = SystemClock.uptimeMillis()
|
||||||
cardsTransitions[container] = CardsTransition(
|
cardsTransitions[container] = CardsTransition(
|
||||||
|
origin,
|
||||||
current,
|
current,
|
||||||
current,
|
moved,
|
||||||
moved = true,
|
|
||||||
stableSince = now,
|
stableSince = now,
|
||||||
deadline = now + TRANSITION_FALLBACK_DELAY,
|
deadline = now + TRANSITION_FALLBACK_DELAY,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package se.ajpanton.notificationsmaster.module
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import java.lang.reflect.Field
|
||||||
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
|
internal fun findField(type: Class<*>, vararg names: String): Field? {
|
||||||
|
var current: Class<*>? = type
|
||||||
|
while (current != null) {
|
||||||
|
names.firstNotNullOfOrNull { runCatching { current.getDeclaredField(it) }.getOrNull() }?.let {
|
||||||
|
it.isAccessible = true
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
current = current.superclass
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun memberAccessor(method: Method?, field: Field?): (Any) -> Any? {
|
||||||
|
method?.isAccessible = true
|
||||||
|
field?.isAccessible = true
|
||||||
|
return if (method != null) ({ method.invoke(it) }) else ({ field!!.get(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun requireField(type: Class<*>, name: String) =
|
||||||
|
findField(type, name) ?: error("${type.name}.$name is unavailable")
|
||||||
|
|
||||||
|
internal class IconStateAccess(type: Class<*>) {
|
||||||
|
private val clampedAmount = requireField(type, "clampedAppearAmount")
|
||||||
|
private val appearAmount = requireField(type, "iconAppearAmount")
|
||||||
|
private val alpha = requireField(type, "mAlpha")
|
||||||
|
private val hidden = requireField(type, "hidden")
|
||||||
|
private val visibleState = requireField(type, "visibleState")
|
||||||
|
|
||||||
|
fun hide(state: Any) {
|
||||||
|
clampedAmount.setFloat(state, 0f)
|
||||||
|
appearAmount.setFloat(state, 0f)
|
||||||
|
alpha.setFloat(state, 0f)
|
||||||
|
hidden.setBoolean(state, true)
|
||||||
|
visibleState.setInt(state, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun currentApplicationContext(): Context? = runCatching {
|
||||||
|
Class.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null) as? Context
|
||||||
|
}.getOrNull()
|
||||||
Reference in New Issue
Block a user