Support AOSP API 34 and Google APIs
This commit is contained in:
@@ -54,7 +54,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "se.ajpanton.navbuttons"
|
||||
minSdk = 35
|
||||
minSdk = 34
|
||||
targetSdk = 35
|
||||
versionCode = project.findProperty("nbVersionCode")?.toString()?.toIntOrNull() ?: 1777070659
|
||||
versionName = project.findProperty("nbVersionName")?.toString() ?: "0.3"
|
||||
|
||||
@@ -48,14 +48,14 @@ import java.util.Collections
|
||||
import java.util.WeakHashMap
|
||||
|
||||
class NavButtons : XposedModule() {
|
||||
private val remotePreferences: SharedPreferences? by lazy(LazyThreadSafetyMode.NONE) {
|
||||
runCatching {
|
||||
getRemotePreferences(NavButtonSettingsStore.PREFERENCES_NAME)
|
||||
}.getOrElse { error ->
|
||||
log("Remote preferences unavailable: ${error.javaClass.simpleName}")
|
||||
null
|
||||
}
|
||||
}
|
||||
@Volatile
|
||||
private var remotePreferences: SharedPreferences? = null
|
||||
|
||||
@Volatile
|
||||
private var remotePreferencesRetryAfterMs = 0L
|
||||
|
||||
@Volatile
|
||||
private var remotePreferencesLoading = false
|
||||
|
||||
private var context: Context? = null
|
||||
private var mainHandler: Handler? = null
|
||||
@@ -140,7 +140,7 @@ class NavButtons : XposedModule() {
|
||||
return
|
||||
}
|
||||
|
||||
if (AOSP_LAUNCHER_PACKAGE == packageName) {
|
||||
if (packageName in AOSP_LAUNCHER_PACKAGES) {
|
||||
if (aospTaskbarHookInstalled) {
|
||||
return
|
||||
}
|
||||
@@ -157,6 +157,56 @@ class NavButtons : XposedModule() {
|
||||
if (mainHandler == null) {
|
||||
mainHandler = Handler(Looper.getMainLooper())
|
||||
}
|
||||
startSettingsPreferencesLoad()
|
||||
}
|
||||
|
||||
private fun getSettingsPreferences(): SharedPreferences? {
|
||||
remotePreferences?.let { return it }
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
startSettingsPreferencesLoad()
|
||||
return null
|
||||
}
|
||||
return loadSettingsPreferences()
|
||||
}
|
||||
|
||||
private fun startSettingsPreferencesLoad() {
|
||||
if (remotePreferences != null || remotePreferencesLoading) {
|
||||
return
|
||||
}
|
||||
val now = SystemClock.uptimeMillis()
|
||||
if (now < remotePreferencesRetryAfterMs) {
|
||||
return
|
||||
}
|
||||
remotePreferencesLoading = true
|
||||
Thread {
|
||||
try {
|
||||
repeat(REMOTE_PREFERENCES_LOAD_ATTEMPTS) {
|
||||
if (loadSettingsPreferences() != null) {
|
||||
return@Thread
|
||||
}
|
||||
Thread.sleep(REMOTE_PREFERENCES_RETRY_DELAY_MS)
|
||||
}
|
||||
} finally {
|
||||
remotePreferencesLoading = false
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun loadSettingsPreferences(): SharedPreferences? {
|
||||
remotePreferences?.let { return it }
|
||||
val now = SystemClock.uptimeMillis()
|
||||
if (now < remotePreferencesRetryAfterMs) {
|
||||
return null
|
||||
}
|
||||
return runCatching {
|
||||
getRemotePreferences(NavButtonSettingsStore.PREFERENCES_NAME)
|
||||
}.getOrElse { error ->
|
||||
remotePreferencesRetryAfterMs = now + REMOTE_PREFERENCES_RETRY_DELAY_MS
|
||||
log("Remote preferences unavailable: ${error.javaClass.simpleName}")
|
||||
null
|
||||
}?.also {
|
||||
remotePreferences = it
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCurrentApplication(): Context? {
|
||||
@@ -170,8 +220,8 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private fun hookSystemUiNavigationButtons(classLoader: ClassLoader?): Boolean {
|
||||
val keyButtonClass = findClassIfExists(SYSTEMUI_KEY_BUTTON_VIEW, classLoader) ?: run {
|
||||
log("SystemUI key button class not found: $SYSTEMUI_KEY_BUTTON_VIEW")
|
||||
val keyButtonClass = findFirstClassIfExists(SYSTEMUI_KEY_BUTTON_VIEW_CLASSES, classLoader) ?: run {
|
||||
log("SystemUI key button class not found: ${SYSTEMUI_KEY_BUTTON_VIEW_CLASSES.joinToString()}")
|
||||
return false
|
||||
}
|
||||
val onTouchEventMethod = findMethodIfExists(
|
||||
@@ -184,7 +234,7 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
val runnableClass = findClassIfExists(
|
||||
"$SYSTEMUI_KEY_BUTTON_VIEW\$1",
|
||||
"${keyButtonClass.name}\$1",
|
||||
classLoader,
|
||||
) ?: run {
|
||||
log("SystemUI long-press runnable not found.")
|
||||
@@ -378,6 +428,16 @@ class NavButtons : XposedModule() {
|
||||
Int::class.javaPrimitiveType!!,
|
||||
)
|
||||
val systemReadyMethod = findMethodIfExists(phoneWindowManagerClass, "systemReady")
|
||||
val keyDispatchMethods = findMethodsNamed(phoneWindowManagerClass, "interceptKeyBeforeDispatching")
|
||||
.filter { method ->
|
||||
method.returnType == Long::class.javaPrimitiveType &&
|
||||
method.parameterTypes.any { it == KeyEvent::class.java }
|
||||
}
|
||||
val keyQueueingMethods = findMethodsNamed(phoneWindowManagerClass, "interceptKeyBeforeQueueing")
|
||||
.filter { method ->
|
||||
method.returnType == Int::class.javaPrimitiveType &&
|
||||
method.parameterTypes.any { it == KeyEvent::class.java }
|
||||
}
|
||||
|
||||
if (systemReadyMethod != null) {
|
||||
deoptimizeMethodIfPresent(systemReadyMethod)
|
||||
@@ -390,6 +450,47 @@ class NavButtons : XposedModule() {
|
||||
installed = true
|
||||
}
|
||||
|
||||
keyDispatchMethods.forEach { method ->
|
||||
deoptimizeMethodIfPresent(method)
|
||||
hook(method).intercept { chain ->
|
||||
val keyEvent = chain.args.firstOrNull { it is KeyEvent } as? KeyEvent
|
||||
?: return@intercept chain.proceed()
|
||||
val buttonId = buttonIdForKeyCode(keyEvent.keyCode) ?: return@intercept chain.proceed()
|
||||
val pressAction = getButtonConfig(buttonId).pressAction
|
||||
if (pressAction == NavButtonAction.STOCK) {
|
||||
return@intercept chain.proceed()
|
||||
}
|
||||
|
||||
updateContextFromField(chain.thisObject, "mContext")
|
||||
if (keyEvent.action == KeyEvent.ACTION_UP && !keyEvent.isCanceled) {
|
||||
performConfiguredAction(pressAction)
|
||||
}
|
||||
-1L
|
||||
}
|
||||
installed = true
|
||||
}
|
||||
|
||||
keyQueueingMethods.forEach { method ->
|
||||
deoptimizeMethodIfPresent(method)
|
||||
hook(method).intercept { chain ->
|
||||
val keyEvent = chain.args.firstOrNull { it is KeyEvent } as? KeyEvent
|
||||
?: return@intercept chain.proceed()
|
||||
val buttonId = buttonIdForKeyCode(keyEvent.keyCode) ?: return@intercept chain.proceed()
|
||||
val pressAction = getButtonConfig(buttonId).pressAction
|
||||
if (pressAction == NavButtonAction.STOCK) {
|
||||
return@intercept chain.proceed()
|
||||
}
|
||||
|
||||
updateContextFromField(chain.thisObject, "mContext")
|
||||
if (keyEvent.action == KeyEvent.ACTION_UP && !keyEvent.isCanceled) {
|
||||
performConfiguredAction(pressAction)
|
||||
}
|
||||
val result = chain.proceed() as? Int ?: 0
|
||||
result and ACTION_PASS_TO_USER.inv()
|
||||
}
|
||||
installed = true
|
||||
}
|
||||
|
||||
if (longPressOnHomeWithEvent != null) {
|
||||
deoptimizeMethodIfPresent(longPressOnHomeWithEvent)
|
||||
hook(longPressOnHomeWithEvent).intercept { chain ->
|
||||
@@ -441,10 +542,13 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private fun hookAospSystemUiSideArrows(classLoader: ClassLoader?, keyButtonClass: Class<*>) {
|
||||
if (aospSystemUiSideArrowHookInstalled || Build.MANUFACTURER.equals("samsung", ignoreCase = true)) {
|
||||
if (aospSystemUiSideArrowHookInstalled ||
|
||||
Build.MANUFACTURER.equals("samsung", ignoreCase = true) ||
|
||||
Build.VERSION.SDK_INT < 35
|
||||
) {
|
||||
return
|
||||
}
|
||||
val inflaterClass = findClassIfExists(AOSP_NAVIGATION_BAR_INFLATER_VIEW, classLoader) ?: return
|
||||
val inflaterClass = findFirstClassIfExists(AOSP_NAVIGATION_BAR_INFLATER_VIEW_CLASSES, classLoader) ?: return
|
||||
aospSystemUiSideArrowHookInstalled = true
|
||||
registerSettingsChangedReceiver()
|
||||
|
||||
@@ -685,8 +789,8 @@ class NavButtons : XposedModule() {
|
||||
val view = value as? View ?: return null
|
||||
val classLoader = view.javaClass.classLoader ?: return null
|
||||
return try {
|
||||
val keyButtonDrawableClass = findClass(AOSP_KEY_BUTTON_DRAWABLE, classLoader)
|
||||
val stateClass = findClass(AOSP_KEY_BUTTON_DRAWABLE_STATE, classLoader)
|
||||
val keyButtonDrawableClass = findFirstClass(AOSP_KEY_BUTTON_DRAWABLE_CLASSES, classLoader)
|
||||
val stateClass = findFirstClass(AOSP_KEY_BUTTON_DRAWABLE_STATE_CLASSES, classLoader)
|
||||
val state = stateClass
|
||||
.getDeclaredConstructor(
|
||||
Int::class.javaPrimitiveType,
|
||||
@@ -743,10 +847,7 @@ class NavButtons : XposedModule() {
|
||||
"sendBackKeyEvent",
|
||||
Int::class.javaPrimitiveType!!,
|
||||
Boolean::class.javaPrimitiveType!!,
|
||||
) ?: run {
|
||||
log("AOSP taskbar sendBackKeyEvent() method not found.")
|
||||
return false
|
||||
}
|
||||
)
|
||||
|
||||
deoptimizeMethodIfPresent(clickMethod)
|
||||
deoptimizeMethodIfPresent(longClickMethod)
|
||||
@@ -791,6 +892,7 @@ class NavButtons : XposedModule() {
|
||||
true
|
||||
}
|
||||
|
||||
if (sendBackKeyEventMethod != null) {
|
||||
hook(sendBackKeyEventMethod).intercept { chain ->
|
||||
val pressAction = getButtonConfig(NavButtonId.BACK).pressAction
|
||||
val longPressAction = getButtonConfig(NavButtonId.BACK).longPressAction
|
||||
@@ -821,6 +923,7 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -1678,7 +1781,7 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private fun sendSideArrowKeyPress(keyCode: Int) {
|
||||
if (context?.packageName == AOSP_LAUNCHER_PACKAGE) {
|
||||
if (context?.packageName in AOSP_LAUNCHER_PACKAGES) {
|
||||
requestPrivilegedAction(PRIVILEGED_ACTION_SEND_KEY_PRESS, keyCode)
|
||||
} else {
|
||||
sendKeyPress(keyCode)
|
||||
@@ -1701,13 +1804,13 @@ class NavButtons : XposedModule() {
|
||||
|
||||
private fun getSideArrowLongPressAction(): SideArrowLongPressAction {
|
||||
return SideArrowLongPressAction.fromStorageValue(
|
||||
remotePreferences?.getString(NavButtonSettingsStore.KEY_SIDE_ARROW_LONG_PRESS_ACTION, null),
|
||||
getSettingsPreferences()?.getString(NavButtonSettingsStore.KEY_SIDE_ARROW_LONG_PRESS_ACTION, null),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getSideArrowLongPressDurationMs(): Int {
|
||||
return (
|
||||
remotePreferences?.getInt(
|
||||
getSettingsPreferences()?.getInt(
|
||||
NavButtonSettingsStore.KEY_SIDE_ARROW_LONG_PRESS_DURATION_MS,
|
||||
ViewConfiguration.getLongPressTimeout(),
|
||||
) ?: ViewConfiguration.getLongPressTimeout()
|
||||
@@ -1716,7 +1819,7 @@ class NavButtons : XposedModule() {
|
||||
|
||||
private fun sideArrowRepeatIntervalMs(): Long {
|
||||
val speed = sanitizeSideArrowRepeatSpeed(
|
||||
remotePreferences?.getFloat(
|
||||
getSettingsPreferences()?.getFloat(
|
||||
NavButtonSettingsStore.KEY_SIDE_ARROW_REPEAT_STEPS_PER_SECOND,
|
||||
NavButtonSettingsStore.DEFAULT_SIDE_ARROW_REPEAT_STEPS_PER_SECOND,
|
||||
) ?: NavButtonSettingsStore.DEFAULT_SIDE_ARROW_REPEAT_STEPS_PER_SECOND,
|
||||
@@ -1886,6 +1989,9 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private fun hookFoldedSideArrows(classLoader: ClassLoader?) {
|
||||
if (!Build.MANUFACTURER.equals("samsung", ignoreCase = true)) {
|
||||
return
|
||||
}
|
||||
hookFoldedLayoutProvider(classLoader)
|
||||
hookSamsungNavigationBarView(classLoader)
|
||||
registerSettingsChangedReceiver()
|
||||
@@ -2237,7 +2343,7 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
sideArrowsEnabledOverride = intent.getBooleanExtra(
|
||||
NavButtonSettingsStore.EXTRA_SIDE_ARROWS_ENABLED,
|
||||
remotePreferences?.getBoolean(NavButtonSettingsStore.KEY_SIDE_ARROWS_ENABLED, false) == true,
|
||||
getSettingsPreferences()?.getBoolean(NavButtonSettingsStore.KEY_SIDE_ARROWS_ENABLED, false) == true,
|
||||
)
|
||||
reInflateTrackedSamsungNavigationBars()
|
||||
refreshTrackedAospSystemUiSideArrowLayouts()
|
||||
@@ -2327,7 +2433,7 @@ class NavButtons : XposedModule() {
|
||||
senderPackage: String?,
|
||||
senderUid: Int,
|
||||
): Boolean {
|
||||
if (senderPackage == AOSP_LAUNCHER_PACKAGE) {
|
||||
if (senderPackage in AOSP_LAUNCHER_PACKAGES) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -2344,11 +2450,11 @@ class NavButtons : XposedModule() {
|
||||
return true
|
||||
}
|
||||
return context.packageManager.getPackagesForUid(senderUid)
|
||||
?.contains(AOSP_LAUNCHER_PACKAGE) == true
|
||||
?.any { it in AOSP_LAUNCHER_PACKAGES } == true
|
||||
}
|
||||
|
||||
private fun readPrivilegedActionToken(): String? {
|
||||
return remotePreferences?.getString(NavButtonSettingsStore.KEY_PRIVILEGED_ACTION_TOKEN, null)
|
||||
return getSettingsPreferences()?.getString(NavButtonSettingsStore.KEY_PRIVILEGED_ACTION_TOKEN, null)
|
||||
}
|
||||
|
||||
private fun requestPrivilegedAction(action: String, keyCode: Int? = null) {
|
||||
@@ -2361,7 +2467,7 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
return
|
||||
}
|
||||
val token = remotePreferences?.getString(
|
||||
val token = getSettingsPreferences()?.getString(
|
||||
NavButtonSettingsStore.KEY_PRIVILEGED_ACTION_TOKEN,
|
||||
null,
|
||||
)
|
||||
@@ -2587,7 +2693,7 @@ class NavButtons : XposedModule() {
|
||||
|
||||
private fun isSideArrowsEnabled(): Boolean {
|
||||
return sideArrowsEnabledOverride
|
||||
?: (remotePreferences?.getBoolean(NavButtonSettingsStore.KEY_SIDE_ARROWS_ENABLED, false) == true)
|
||||
?: (getSettingsPreferences()?.getBoolean(NavButtonSettingsStore.KEY_SIDE_ARROWS_ENABLED, false) == true)
|
||||
}
|
||||
|
||||
private fun injectKeyEvent(inputManager: Any, keyEvent: KeyEvent) {
|
||||
@@ -2773,7 +2879,7 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
|
||||
private fun getButtonConfig(buttonId: NavButtonId): NavButtonConfig {
|
||||
val preferences = remotePreferences
|
||||
val preferences = getSettingsPreferences()
|
||||
val defaultDurationMs = ViewConfiguration.getLongPressTimeout().coerceLongPressDuration()
|
||||
return NavButtonConfig(
|
||||
pressAction = NavButtonAction.fromStorageValue(
|
||||
@@ -2828,7 +2934,7 @@ class NavButtons : XposedModule() {
|
||||
return packageName == null ||
|
||||
packageName == SYSTEMUI_PACKAGE ||
|
||||
packageName == SAMSUNG_LAUNCHER_PACKAGE ||
|
||||
packageName == AOSP_LAUNCHER_PACKAGE ||
|
||||
packageName in AOSP_LAUNCHER_PACKAGES ||
|
||||
packageName == defaultLauncher
|
||||
}
|
||||
|
||||
@@ -3137,6 +3243,22 @@ class NavButtons : XposedModule() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun findFirstClass(classNames: List<String>, classLoader: ClassLoader?): Class<*> {
|
||||
classNames.forEach { className ->
|
||||
findClassIfExists(className, classLoader)?.let { return it }
|
||||
}
|
||||
throw ClassNotFoundException(classNames.joinToString())
|
||||
}
|
||||
|
||||
private fun findFirstClassIfExists(
|
||||
classNames: List<String>,
|
||||
classLoader: ClassLoader?,
|
||||
): Class<*>? {
|
||||
return classNames.firstNotNullOfOrNull { className ->
|
||||
findClassIfExists(className, classLoader)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findMethodIfExists(
|
||||
clazz: Class<*>,
|
||||
methodName: String,
|
||||
@@ -3361,14 +3483,19 @@ class NavButtons : XposedModule() {
|
||||
const val ASSIST_INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS = 5
|
||||
const val INPUT_MANAGER_CLASS = "android.hardware.input.InputManager"
|
||||
const val INPUT_EVENT_INJECTION_SYNC_NONE = 0
|
||||
const val ACTION_PASS_TO_USER = 1
|
||||
const val HOME_LONG_PRESS_DEDUP_WINDOW_MS = 1_000L
|
||||
const val REMOTE_PREFERENCES_RETRY_DELAY_MS = 1_000L
|
||||
const val REMOTE_PREFERENCES_LOAD_ATTEMPTS = 15
|
||||
const val STOCK_LONG_PRESS_GUARD_EARLY_MS = 75
|
||||
const val STOCK_LONG_PRESS_GUARD_MIN_DELAY_MS = 100
|
||||
const val SYSTEMUI_PACKAGE = "com.android.systemui"
|
||||
const val ANDROID_PACKAGE = "android"
|
||||
const val SYSTEM_SERVER_PHONE_WINDOW_MANAGER = "com.android.server.policy.PhoneWindowManager"
|
||||
const val SYSTEMUI_KEY_BUTTON_VIEW =
|
||||
"com.android.systemui.navigationbar.views.buttons.KeyButtonView"
|
||||
val SYSTEMUI_KEY_BUTTON_VIEW_CLASSES = listOf(
|
||||
"com.android.systemui.navigationbar.views.buttons.KeyButtonView",
|
||||
"com.android.systemui.navigationbar.buttons.KeyButtonView",
|
||||
)
|
||||
const val SAMSUNG_PHONE_LAYOUT_PROVIDER =
|
||||
"com.android.systemui.navigationbar.layout.LayoutProviderImpl"
|
||||
const val SAMSUNG_TABLET_LAYOUT_PROVIDER =
|
||||
@@ -3376,7 +3503,10 @@ class NavButtons : XposedModule() {
|
||||
const val SAMSUNG_NAVIGATION_BAR_VIEW =
|
||||
"com.android.systemui.navigationbar.views.SamsungNavigationBarView"
|
||||
const val SAMSUNG_LAUNCHER_PACKAGE = "com.sec.android.app.launcher"
|
||||
const val AOSP_LAUNCHER_PACKAGE = "com.android.launcher3"
|
||||
val AOSP_LAUNCHER_PACKAGES = setOf(
|
||||
"com.android.launcher3",
|
||||
"com.google.android.apps.nexuslauncher",
|
||||
)
|
||||
const val AOSP_TASKBAR_NAV_BUTTON_CONTROLLER =
|
||||
"com.android.launcher3.taskbar.TaskbarNavButtonController"
|
||||
const val AOSP_TASKBAR_BACK_BUTTON = 1
|
||||
@@ -3385,12 +3515,18 @@ class NavButtons : XposedModule() {
|
||||
const val AOSP_NAVBAR_BUTTONS_VIEW_CONTROLLER =
|
||||
"com.android.launcher3.taskbar.NavbarButtonsViewController"
|
||||
const val AOSP_TASKBAR_SIDE_BUTTON_SHIFT_RATIO = 0.45f
|
||||
const val AOSP_NAVIGATION_BAR_INFLATER_VIEW =
|
||||
"com.android.systemui.navigationbar.views.NavigationBarInflaterView"
|
||||
const val AOSP_KEY_BUTTON_DRAWABLE =
|
||||
"com.android.systemui.navigationbar.views.buttons.KeyButtonDrawable"
|
||||
const val AOSP_KEY_BUTTON_DRAWABLE_STATE =
|
||||
"com.android.systemui.navigationbar.views.buttons.KeyButtonDrawable\$ShadowDrawableState"
|
||||
val AOSP_NAVIGATION_BAR_INFLATER_VIEW_CLASSES = listOf(
|
||||
"com.android.systemui.navigationbar.views.NavigationBarInflaterView",
|
||||
"com.android.systemui.navigationbar.NavigationBarInflaterView",
|
||||
)
|
||||
val AOSP_KEY_BUTTON_DRAWABLE_CLASSES = listOf(
|
||||
"com.android.systemui.navigationbar.views.buttons.KeyButtonDrawable",
|
||||
"com.android.systemui.navigationbar.buttons.KeyButtonDrawable",
|
||||
)
|
||||
val AOSP_KEY_BUTTON_DRAWABLE_STATE_CLASSES = listOf(
|
||||
"com.android.systemui.navigationbar.views.buttons.KeyButtonDrawable\$ShadowDrawableState",
|
||||
"com.android.systemui.navigationbar.buttons.KeyButtonDrawable\$ShadowDrawableState",
|
||||
)
|
||||
const val AOSP_SYSUI_LEFT_ARROW_BUTTON = "key(21)"
|
||||
const val AOSP_SYSUI_RIGHT_ARROW_BUTTON = "key(22)"
|
||||
const val ACTION_PRIVILEGED_ACTION =
|
||||
|
||||
@@ -2,5 +2,6 @@ android
|
||||
system
|
||||
com.android.systemui
|
||||
com.android.launcher3
|
||||
com.google.android.apps.nexuslauncher
|
||||
com.sec.android.app.launcher
|
||||
com.samsung.systemui.navillera
|
||||
|
||||
Reference in New Issue
Block a user