Skip to content

Commit 4ab4b42

Browse files
feat: add native path hiding, expressive UI components and dark mode fixes
- Port root-hide KPM to KernelPatch native capability with supercall interface - Add ExpressiveCard/ExpressiveSwitch components with thumb icons - Add path hide UI with toggle and configuration in FunctionSettings - Fix dark mode text color across all settings screens (onSurface) - Add kernel spoof and path hide i18n for all 18 locales - Unify settings hub icons and SplicedColumnGroup layout
1 parent cdcf40a commit 4ab4b42

43 files changed

Lines changed: 1266 additions & 176 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/src/main/cpp/apjni.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,75 @@ jlong nativeUtsReset(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {
280280
return rc;
281281
}
282282

283+
jlong nativePathHideAdd(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jstring path_jstr) {
284+
ensureSuperKeyNonNull(super_key_jstr);
285+
286+
const auto super_key = JUTFString(env, super_key_jstr);
287+
const auto path = JUTFString(env, path_jstr);
288+
long rc = sc_pathhide_add(super_key.get(), path.get());
289+
if (rc < 0) [[unlikely]] {
290+
LOGE("nativePathHideAdd error: %ld", rc);
291+
}
292+
return rc;
293+
}
294+
295+
jlong nativePathHideRemove(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jstring path_jstr) {
296+
ensureSuperKeyNonNull(super_key_jstr);
297+
298+
const auto super_key = JUTFString(env, super_key_jstr);
299+
const auto path = JUTFString(env, path_jstr);
300+
long rc = sc_pathhide_remove(super_key.get(), path.get());
301+
if (rc < 0) [[unlikely]] {
302+
LOGE("nativePathHideRemove error: %ld", rc);
303+
}
304+
return rc;
305+
}
306+
307+
jstring nativePathHideList(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {
308+
ensureSuperKeyNonNull(super_key_jstr);
309+
310+
const auto super_key = JUTFString(env, super_key_jstr);
311+
char buf[4096] = { '\0' };
312+
long rc = sc_pathhide_list(super_key.get(), buf, sizeof(buf));
313+
if (rc < 0) [[unlikely]] {
314+
LOGE("nativePathHideList error: %ld", rc);
315+
}
316+
return env->NewStringUTF(buf);
317+
}
318+
319+
jlong nativePathHideClear(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {
320+
ensureSuperKeyNonNull(super_key_jstr);
321+
322+
const auto super_key = JUTFString(env, super_key_jstr);
323+
long rc = sc_pathhide_clear(super_key.get());
324+
if (rc < 0) [[unlikely]] {
325+
LOGE("nativePathHideClear error: %ld", rc);
326+
}
327+
return rc;
328+
}
329+
330+
jlong nativePathHideEnable(JNIEnv *env, jobject /* this */, jstring super_key_jstr, jint enable) {
331+
ensureSuperKeyNonNull(super_key_jstr);
332+
333+
const auto super_key = JUTFString(env, super_key_jstr);
334+
long rc = sc_pathhide_enable(super_key.get(), enable);
335+
if (rc < 0) [[unlikely]] {
336+
LOGE("nativePathHideEnable error: %ld", rc);
337+
}
338+
return rc;
339+
}
340+
341+
jlong nativePathHideStatus(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {
342+
ensureSuperKeyNonNull(super_key_jstr);
343+
344+
const auto super_key = JUTFString(env, super_key_jstr);
345+
long rc = sc_pathhide_status(super_key.get());
346+
if (rc < 0) [[unlikely]] {
347+
LOGE("nativePathHideStatus error: %ld", rc);
348+
}
349+
return rc;
350+
}
351+
283352
jstring nativeSuAuditList(JNIEnv *env, jobject /* this */, jstring super_key_jstr) {
284353
ensureSuperKeyNonNull(super_key_jstr);
285354

@@ -370,6 +439,12 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void * /*reserved*/) {
370439
{"nativeResetSuPath", "(Ljava/lang/String;Ljava/lang/String;)Z", reinterpret_cast<void *>(&nativeResetSuPath)},
371440
{"nativeUtsSet", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)J", reinterpret_cast<void *>(&nativeUtsSet)},
372441
{"nativeUtsReset", "(Ljava/lang/String;)J", reinterpret_cast<void *>(&nativeUtsReset)},
442+
{"nativePathHideAdd", "(Ljava/lang/String;Ljava/lang/String;)J", reinterpret_cast<void *>(&nativePathHideAdd)},
443+
{"nativePathHideRemove", "(Ljava/lang/String;Ljava/lang/String;)J", reinterpret_cast<void *>(&nativePathHideRemove)},
444+
{"nativePathHideList", "(Ljava/lang/String;)Ljava/lang/String;", reinterpret_cast<void *>(&nativePathHideList)},
445+
{"nativePathHideClear", "(Ljava/lang/String;)J", reinterpret_cast<void *>(&nativePathHideClear)},
446+
{"nativePathHideEnable", "(Ljava/lang/String;I)J", reinterpret_cast<void *>(&nativePathHideEnable)},
447+
{"nativePathHideStatus", "(Ljava/lang/String;)J", reinterpret_cast<void *>(&nativePathHideStatus)},
373448
{"nativeSuAuditList", "(Ljava/lang/String;)Ljava/lang/String;", reinterpret_cast<void *>(&nativeSuAuditList)},
374449
{"nativeSuAuditClear", "(Ljava/lang/String;)J", reinterpret_cast<void *>(&nativeSuAuditClear)},
375450
{"nativeGetApiToken", "(Landroid/content/Context;)Ljava/lang/String;", reinterpret_cast<void *>(&nativeGetApiToken)},

app/src/main/cpp/supercall.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,4 +610,43 @@ static inline long sc_uts_reset(const char *key)
610610
return ret;
611611
}
612612

613+
static inline long sc_pathhide_add(const char *key, const char *path)
614+
{
615+
if (!key || !key[0]) return -EINVAL;
616+
if (!path || !path[0]) return -EINVAL;
617+
return syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_PATHHIDE_ADD), path);
618+
}
619+
620+
static inline long sc_pathhide_remove(const char *key, const char *path)
621+
{
622+
if (!key || !key[0]) return -EINVAL;
623+
if (!path || !path[0]) return -EINVAL;
624+
return syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_PATHHIDE_REMOVE), path);
625+
}
626+
627+
static inline long sc_pathhide_list(const char *key, char *out_buf, int outlen)
628+
{
629+
if (!key || !key[0]) return -EINVAL;
630+
if (!out_buf || outlen <= 0) return -EINVAL;
631+
return syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_PATHHIDE_LIST), out_buf, outlen);
632+
}
633+
634+
static inline long sc_pathhide_clear(const char *key)
635+
{
636+
if (!key || !key[0]) return -EINVAL;
637+
return syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_PATHHIDE_CLEAR));
638+
}
639+
640+
static inline long sc_pathhide_enable(const char *key, int enable)
641+
{
642+
if (!key || !key[0]) return -EINVAL;
643+
return syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_PATHHIDE_ENABLE), (long)enable);
644+
}
645+
646+
static inline long sc_pathhide_status(const char *key)
647+
{
648+
if (!key || !key[0]) return -EINVAL;
649+
return syscall(__NR_supercall, key, ver_and_cmd(key, SUPERCALL_PATHHIDE_STATUS));
650+
}
651+
613652
#endif

app/src/main/cpp/uapi/scdefs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ struct kernel_storage
5858
#define SUPERCALL_UTS_SET 0x1050
5959
#define SUPERCALL_UTS_RESET 0x1051
6060

61+
#define SUPERCALL_PATHHIDE_ADD 0x1060
62+
#define SUPERCALL_PATHHIDE_REMOVE 0x1061
63+
#define SUPERCALL_PATHHIDE_LIST 0x1062
64+
#define SUPERCALL_PATHHIDE_CLEAR 0x1063
65+
#define SUPERCALL_PATHHIDE_ENABLE 0x1064
66+
#define SUPERCALL_PATHHIDE_STATUS 0x1065
67+
6168
#define KSTORAGE_SU_LIST_GROUP 0
6269
#define KSTORAGE_EXCLUDE_LIST_GROUP 1
6370
#define KSTORAGE_SU_AUDIT_GROUP 2

app/src/main/java/me/bmax/apatch/APatchApp.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ class APApplication : Application(), Thread.UncaughtExceptionHandler, ImageLoade
102102
const val UMOUNT_BINARY_PATH = "/data/adb/fp/bin/fpd"
103103
const val UTS_SPOOF_ENABLE_FILE = "/data/adb/.uts_spoof_enable"
104104
const val UTS_SPOOF_CONFIG_FILE = "/data/adb/.uts_spoof_config"
105+
const val PATHHIDE_DIR = "/data/adb/fp/pathhide/"
106+
const val PATHHIDE_PATHS_FILE = "/data/adb/fp/pathhide/paths"
107+
const val PATHHIDE_ENABLE_FILE = "/data/adb/fp/pathhide/enabled"
105108
const val KPMS_DIR = APATCH_FOLDER + "kpms/"
106109

107110
@Deprecated("Use SHA256 comparison instead")

app/src/main/java/me/bmax/apatch/Natives.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,42 @@ object Natives {
166166
return nativeUtsReset(APApplication.superKey)
167167
}
168168

169+
@FastNative
170+
private external fun nativePathHideAdd(superKey: String, path: String): Long
171+
fun pathHideAdd(path: String): Long {
172+
return nativePathHideAdd(APApplication.superKey, path)
173+
}
174+
175+
@FastNative
176+
private external fun nativePathHideRemove(superKey: String, path: String): Long
177+
fun pathHideRemove(path: String): Long {
178+
return nativePathHideRemove(APApplication.superKey, path)
179+
}
180+
181+
@FastNative
182+
private external fun nativePathHideList(superKey: String): String
183+
fun pathHideList(): String {
184+
return nativePathHideList(APApplication.superKey)
185+
}
186+
187+
@FastNative
188+
private external fun nativePathHideClear(superKey: String): Long
189+
fun pathHideClear(): Long {
190+
return nativePathHideClear(APApplication.superKey)
191+
}
192+
193+
@FastNative
194+
private external fun nativePathHideEnable(superKey: String, enable: Int): Long
195+
fun pathHideEnable(enable: Boolean): Long {
196+
return nativePathHideEnable(APApplication.superKey, if (enable) 1 else 0)
197+
}
198+
199+
@FastNative
200+
private external fun nativePathHideStatus(superKey: String): Long
201+
fun pathHideStatus(): Long {
202+
return nativePathHideStatus(APApplication.superKey)
203+
}
204+
169205
@FastNative
170206
private external fun nativeSuAuditList(superKey: String): String
171207
fun suAuditList(): String {

app/src/main/java/me/bmax/apatch/ui/component/ExpressiveCard.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package me.bmax.apatch.ui.component
22

3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.interaction.MutableInteractionSource
5+
import androidx.compose.foundation.layout.Box
36
import androidx.compose.foundation.layout.fillMaxWidth
47
import androidx.compose.foundation.shape.RoundedCornerShape
58
import androidx.compose.material3.Card
69
import androidx.compose.material3.CardDefaults
710
import androidx.compose.material3.ElevatedCard
811
import androidx.compose.material3.MaterialTheme
12+
import androidx.compose.material3.ripple
913
import androidx.compose.runtime.Composable
14+
import androidx.compose.runtime.remember
1015
import androidx.compose.ui.Modifier
1116
import androidx.compose.ui.unit.dp
1217

@@ -17,6 +22,29 @@ fun ExpressiveCard(
1722
flat: Boolean = false,
1823
content: @Composable () -> Unit,
1924
) {
25+
if (LocalInsideSplicedGroup.current) {
26+
// Inside SplicedColumnGroup: skip card wrapper, parent provides container
27+
if (onClick != null) {
28+
Box(
29+
modifier = modifier
30+
.fillMaxWidth()
31+
.clickable(
32+
interactionSource = remember { MutableInteractionSource() },
33+
indication = ripple(),
34+
onClick = onClick,
35+
),
36+
) {
37+
content()
38+
}
39+
} else {
40+
Box(modifier = modifier.fillMaxWidth()) {
41+
content()
42+
}
43+
}
44+
return
45+
}
46+
47+
// Standalone: use Card/ElevatedCard with rounded corners
2048
val shape = RoundedCornerShape(32.dp)
2149
val colors = if (flat) {
2250
CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainer)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package me.bmax.apatch.ui.component
2+
3+
import androidx.compose.foundation.interaction.MutableInteractionSource
4+
import androidx.compose.foundation.layout.size
5+
import androidx.compose.material.icons.Icons
6+
import androidx.compose.material.icons.filled.Check
7+
import androidx.compose.material.icons.filled.Close
8+
import androidx.compose.material3.Icon
9+
import androidx.compose.material3.MaterialTheme
10+
import androidx.compose.material3.Switch
11+
import androidx.compose.material3.SwitchColors
12+
import androidx.compose.material3.SwitchDefaults
13+
import androidx.compose.runtime.Composable
14+
import androidx.compose.runtime.getValue
15+
import androidx.compose.runtime.mutableStateOf
16+
import androidx.compose.runtime.remember
17+
import androidx.compose.runtime.setValue
18+
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.graphics.vector.ImageVector
20+
import me.bmax.apatch.APApplication
21+
22+
object SwitchIconState {
23+
var showIcon by mutableStateOf(
24+
APApplication.sharedPreferences.getBoolean("show_switch_icon", false)
25+
)
26+
}
27+
28+
@Composable
29+
fun ExpressiveSwitch(
30+
checked: Boolean,
31+
onCheckedChange: ((Boolean) -> Unit)?,
32+
modifier: Modifier = Modifier,
33+
enabled: Boolean = true,
34+
colors: SwitchColors = SwitchDefaults.colors(),
35+
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
36+
) {
37+
Switch(
38+
checked = checked,
39+
onCheckedChange = onCheckedChange,
40+
modifier = modifier,
41+
enabled = enabled,
42+
colors = colors,
43+
interactionSource = interactionSource,
44+
thumbContent = if (SwitchIconState.showIcon) {
45+
{
46+
if (checked) {
47+
ThumbIcon(Icons.Filled.Check, MaterialTheme.colorScheme.primary)
48+
} else {
49+
ThumbIcon(Icons.Filled.Close, MaterialTheme.colorScheme.surfaceContainerHighest)
50+
}
51+
}
52+
} else null,
53+
)
54+
}
55+
56+
@Composable
57+
private fun ThumbIcon(icon: ImageVector, tint: androidx.compose.ui.graphics.Color) {
58+
Icon(
59+
imageVector = icon,
60+
contentDescription = null,
61+
tint = tint,
62+
modifier = Modifier.size(SwitchDefaults.IconSize),
63+
)
64+
}

app/src/main/java/me/bmax/apatch/ui/component/SettingsItem.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import androidx.compose.material3.ListItem
88
import androidx.compose.material3.LocalContentColor
99
import androidx.compose.material3.MaterialTheme
1010
import androidx.compose.material3.RadioButton
11-
import androidx.compose.material3.Switch
1211
import androidx.compose.material3.Text
1312
import androidx.compose.runtime.Composable
1413
import androidx.compose.runtime.remember
@@ -111,7 +110,7 @@ fun SwitchItem(
111110
}
112111
} else null,
113112
trailingContent = {
114-
Switch(
113+
ExpressiveSwitch(
115114
checked = checked,
116115
onCheckedChange = null,
117116
enabled = enabled

0 commit comments

Comments
 (0)