mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 08:07:25 +00:00
Compare commits
680 Commits
v17.3
...
manager-v7
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4040a0242f | ||
![]() |
781ec810d9 | ||
![]() |
9e90a71c04 | ||
![]() |
5571714b26 | ||
![]() |
e0d1f02ef5 | ||
![]() |
1b729e5ff2 | ||
![]() |
51e587d4e8 | ||
![]() |
ac9c55dbc1 | ||
![]() |
0893ac3141 | ||
![]() |
fb40e96917 | ||
![]() |
4ca25f74c6 | ||
![]() |
7fda917b86 | ||
![]() |
e6bd5f2c40 | ||
![]() |
8a904ee384 | ||
![]() |
00a9f18a1e | ||
![]() |
8d68ebb074 | ||
![]() |
5f53cfb4a9 | ||
![]() |
a2fa8d8be1 | ||
![]() |
70a3c78ebb | ||
![]() |
54d1207f92 | ||
![]() |
003e44fb84 | ||
![]() |
515f346dcc | ||
![]() |
6050c4e8ba | ||
![]() |
158af8819a | ||
![]() |
7787bb31fa | ||
![]() |
a1fe3e7ccd | ||
![]() |
4316028b23 | ||
![]() |
f2b52755d6 | ||
![]() |
f315c4416b | ||
![]() |
4e7dafb0e4 | ||
![]() |
a6395d35db | ||
![]() |
a028cd5cec | ||
![]() |
540000d26e | ||
![]() |
888c656aa8 | ||
![]() |
8d4c407201 | ||
![]() |
fdeede23f7 | ||
![]() |
53c5ca59b6 | ||
![]() |
679db97209 | ||
![]() |
fbdd72273e | ||
![]() |
0165602515 | ||
![]() |
96127f8bd1 | ||
![]() |
0dbdf336d6 | ||
![]() |
48879df2da | ||
![]() |
b067a5bb13 | ||
![]() |
4b54cf1288 | ||
![]() |
6128c24f96 | ||
![]() |
d9c58f307f | ||
![]() |
b521fbeeda | ||
![]() |
d00a3b89f2 | ||
![]() |
3d15518191 | ||
![]() |
9b6535fdf5 | ||
![]() |
e0424fdba3 | ||
![]() |
7481c53451 | ||
![]() |
7219947237 | ||
![]() |
b72004e9cc | ||
![]() |
f187213568 | ||
![]() |
fc0df84edd | ||
![]() |
f24df4f43d | ||
![]() |
dab32e1599 | ||
![]() |
bc286fd4d3 | ||
![]() |
befe1a83b5 | ||
![]() |
82ea9db9fd | ||
![]() |
c5758b3f2d | ||
![]() |
ace3708c9c | ||
![]() |
fc5026d268 | ||
![]() |
77fd0e54be | ||
![]() |
24490e0ff5 | ||
![]() |
da3937ff4e | ||
![]() |
ebe1ab982e | ||
![]() |
98590cb00d | ||
![]() |
ff95f634f0 | ||
![]() |
ced9b4a8ee | ||
![]() |
7af7910e78 | ||
![]() |
a4f5d47e72 | ||
![]() |
6953cc2411 | ||
![]() |
6a0b2ddee9 | ||
![]() |
24f5bc98d8 | ||
![]() |
5203886f0b | ||
![]() |
c10b376575 | ||
![]() |
ceb21ced2b | ||
![]() |
86789a8694 | ||
![]() |
ca2235aee7 | ||
![]() |
a385e5cd92 | ||
![]() |
0c7a95bdf6 | ||
![]() |
036b5acf42 | ||
![]() |
056dafc59f | ||
![]() |
a9c90718d6 | ||
![]() |
cc77a24502 | ||
![]() |
71a91ac7a7 | ||
![]() |
08a70f033a | ||
![]() |
1b0c36dbd5 | ||
![]() |
91da1cf817 | ||
![]() |
c577a9525d | ||
![]() |
0149b1368d | ||
![]() |
cd6bcb97ef | ||
![]() |
df4161ffcc | ||
![]() |
7a133eaf03 | ||
![]() |
1cd45b53b1 | ||
![]() |
5b30c77403 | ||
![]() |
8248480d56 | ||
![]() |
345d992d39 | ||
![]() |
a7f6afa4bc | ||
![]() |
d22c7de79a | ||
![]() |
3eae9494ce | ||
![]() |
be7e737253 | ||
![]() |
b6eb912dba | ||
![]() |
8049b08918 | ||
![]() |
d1fa5be210 | ||
![]() |
fdbb1af02c | ||
![]() |
c85a5cae88 | ||
![]() |
649ef53409 | ||
![]() |
e784212283 | ||
![]() |
66eb1078fe | ||
![]() |
1c09b3642f | ||
![]() |
d08b1a6639 | ||
![]() |
10f50e2401 | ||
![]() |
8e9a7b25a1 | ||
![]() |
4859ee2da9 | ||
![]() |
b45db44ad9 | ||
![]() |
e25ce63872 | ||
![]() |
162eeaa0a6 | ||
![]() |
f36ce905aa | ||
![]() |
8ac3aaf36c | ||
![]() |
a199b0ace1 | ||
![]() |
2f2108e4e8 | ||
![]() |
f5f7fd9132 | ||
![]() |
f9ae4ab475 | ||
![]() |
8de03eef3f | ||
![]() |
8df942f96e | ||
![]() |
9bb2243b56 | ||
![]() |
db06038548 | ||
![]() |
ecb33d3176 | ||
![]() |
eae1c17738 | ||
![]() |
ea55532e33 | ||
![]() |
2a40cb60a9 | ||
![]() |
d371d017b7 | ||
![]() |
1d9359d563 | ||
![]() |
945f88105f | ||
![]() |
957feca626 | ||
![]() |
c0447009db | ||
![]() |
8893cbd64a | ||
![]() |
f0240b1f06 | ||
![]() |
e476c18c99 | ||
![]() |
a1b5185ecb | ||
![]() |
981e90cc32 | ||
![]() |
da0a72e8b0 | ||
![]() |
b7e2e972c7 | ||
![]() |
650b2ce6b1 | ||
![]() |
ecf3d30349 | ||
![]() |
15ddd0e284 | ||
![]() |
18ac6b270f | ||
![]() |
3e35de9b39 | ||
![]() |
1e24c72c11 | ||
![]() |
217564963d | ||
![]() |
f2f4649ab0 | ||
![]() |
4395ffec5f | ||
![]() |
9a7a26407a | ||
![]() |
5072a67807 | ||
![]() |
dce0b6c05a | ||
![]() |
a4a661bf34 | ||
![]() |
771e500468 | ||
![]() |
7e3ff03109 | ||
![]() |
a1827fd680 | ||
![]() |
9ce334feac | ||
![]() |
ed11e0bff6 | ||
![]() |
5111086637 | ||
![]() |
20f204810e | ||
![]() |
4581354e7a | ||
![]() |
faf4d76388 | ||
![]() |
a46e255709 | ||
![]() |
63e2bbb4d1 | ||
![]() |
c3dabae237 | ||
![]() |
f1abcbb7fb | ||
![]() |
70efddb90f | ||
![]() |
f24a5dfd45 | ||
![]() |
081074ad9d | ||
![]() |
ab0cc78d2c | ||
![]() |
de5c902fdb | ||
![]() |
cf65169c99 | ||
![]() |
745865ee53 | ||
![]() |
c134fb1939 | ||
![]() |
0204d05316 | ||
![]() |
c345633d80 | ||
![]() |
a57a94040e | ||
![]() |
1bde78d121 | ||
![]() |
bbd014ad1b | ||
![]() |
1287372f5a | ||
![]() |
d2cb638fcd | ||
![]() |
bbe4b69c8d | ||
![]() |
7f08c06943 | ||
![]() |
8f4a6415cd | ||
![]() |
0442d6d509 | ||
![]() |
a3fc6d2a27 | ||
![]() |
7db05ac927 | ||
![]() |
8bed93b3c5 | ||
![]() |
915b49014f | ||
![]() |
c699f30831 | ||
![]() |
3e73e3a906 | ||
![]() |
32c65d8a88 | ||
![]() |
a49328edd3 | ||
![]() |
9a15365a57 | ||
![]() |
82c864d57e | ||
![]() |
6226f875ff | ||
![]() |
370015a853 | ||
![]() |
6597b7adc0 | ||
![]() |
4e53ebfe44 | ||
![]() |
04ef1e6405 | ||
![]() |
b278d07b05 | ||
![]() |
6c3896079d | ||
![]() |
e73fa57d54 | ||
![]() |
eaa9c7e2a0 | ||
![]() |
14ae29d907 | ||
![]() |
e8f35b02ca | ||
![]() |
dee3c3e7ba | ||
![]() |
d8cd2031c7 | ||
![]() |
7203e7df5c | ||
![]() |
b51feffe80 | ||
![]() |
b1afd554fc | ||
![]() |
885e3c574b | ||
![]() |
05dd5f3396 | ||
![]() |
ec3c43faf1 | ||
![]() |
e72c6685ed | ||
![]() |
99d6bd8efc | ||
![]() |
4c8587a9f2 | ||
![]() |
54a8a05dae | ||
![]() |
164a99681b | ||
![]() |
0eef4eacd6 | ||
![]() |
5764f0c839 | ||
![]() |
f28e425542 | ||
![]() |
d1a4f046e9 | ||
![]() |
2ce1dc4afe | ||
![]() |
37ac249fd7 | ||
![]() |
f152bea8d8 | ||
![]() |
7b089b888a | ||
![]() |
68f0e1fe39 | ||
![]() |
8032bd0bac | ||
![]() |
0c227f2917 | ||
![]() |
c9fa8118d1 | ||
![]() |
63b18246d8 | ||
![]() |
16ec37a226 | ||
![]() |
bd4e5bfc1a | ||
![]() |
621fd0ee29 | ||
![]() |
6ca8db2f0c | ||
![]() |
ea129fb206 | ||
![]() |
3356d7b6ff | ||
![]() |
c84023bdc2 | ||
![]() |
86f778c0aa | ||
![]() |
defbbdfe21 | ||
![]() |
0f46493477 | ||
![]() |
340bac7e42 | ||
![]() |
1d3ce9fef1 | ||
![]() |
4a398642b8 | ||
![]() |
9c89e56c56 | ||
![]() |
267c59b1f1 | ||
![]() |
2ab17204c6 | ||
![]() |
75939047d1 | ||
![]() |
2d7f130d2c | ||
![]() |
f7ae72a36c | ||
![]() |
391783e268 | ||
![]() |
6f12c08204 | ||
![]() |
cb8fe70734 | ||
![]() |
69d10b747a | ||
![]() |
da3394f34e | ||
![]() |
b4c2a9f49f | ||
![]() |
7cee77f57a | ||
![]() |
f28bd1972f | ||
![]() |
0f92d1de1b | ||
![]() |
e59c5c8780 | ||
![]() |
86d8026301 | ||
![]() |
d67b827338 | ||
![]() |
660e0dc09a | ||
![]() |
3ebc886f8a | ||
![]() |
5b54ef840a | ||
![]() |
c08b0d4974 | ||
![]() |
7d652afd87 | ||
![]() |
0f61c627b1 | ||
![]() |
7126648404 | ||
![]() |
4a5e2dc9c7 | ||
![]() |
10613686ed | ||
![]() |
17ab55115a | ||
![]() |
2708c74ebe | ||
![]() |
50ff11405f | ||
![]() |
31a27838f5 | ||
![]() |
2f1b0fe57f | ||
![]() |
692f893e1f | ||
![]() |
14aa6041ec | ||
![]() |
fb55fe184c | ||
![]() |
6412bfc7b5 | ||
![]() |
3c56f38229 | ||
![]() |
f4f2274c60 | ||
![]() |
19ee189468 | ||
![]() |
a19c7215d2 | ||
![]() |
8b84039f1f | ||
![]() |
9430dbb96c | ||
![]() |
4872df6a46 | ||
![]() |
014105f0a0 | ||
![]() |
b106d1c501 | ||
![]() |
99db0672b4 | ||
![]() |
d584360de2 | ||
![]() |
4eed6794c7 | ||
![]() |
c66cabd80f | ||
![]() |
24da3485bd | ||
![]() |
7384d2d330 | ||
![]() |
e5940168fe | ||
![]() |
6855baf0f8 | ||
![]() |
dfd16e8fef | ||
![]() |
98a36819bc | ||
![]() |
de8bc9ca9d | ||
![]() |
c137f2de4f | ||
![]() |
0f55fcafe8 | ||
![]() |
ed027ec3ee | ||
![]() |
b3fd79cbb9 | ||
![]() |
ed4df87b57 | ||
![]() |
1321f097b8 | ||
![]() |
cfa28f0c4a | ||
![]() |
ab47b717b1 | ||
![]() |
65ebb0d2f8 | ||
![]() |
49640ce03a | ||
![]() |
e05cdc83f3 | ||
![]() |
992a9ea2f9 | ||
![]() |
228351fc13 | ||
![]() |
8a5b6f2b86 | ||
![]() |
71ecbb3af3 | ||
![]() |
5746614ccf | ||
![]() |
3a422c3f15 | ||
![]() |
b3242322fd | ||
![]() |
9826640ae6 | ||
![]() |
1f5267204b | ||
![]() |
ed25e1bbd6 | ||
![]() |
c8491d008f | ||
![]() |
08e3405394 | ||
![]() |
4ebfa07186 | ||
![]() |
6698c189fc | ||
![]() |
f0639390aa | ||
![]() |
bbdfed2d5a | ||
![]() |
7f4daa2c50 | ||
![]() |
baf9b67b35 | ||
![]() |
caf73b0b36 | ||
![]() |
acf87c2794 | ||
![]() |
7f5f6b54fb | ||
![]() |
a08eb8a446 | ||
![]() |
b31402766e | ||
![]() |
9ab3143bf0 | ||
![]() |
81a0cddb9e | ||
![]() |
f620ac769f | ||
![]() |
dc91041edd | ||
![]() |
6ee08b6717 | ||
![]() |
5a2cd2ac84 | ||
![]() |
2bd8448aaa | ||
![]() |
2360adb592 | ||
![]() |
c7301a5161 | ||
![]() |
72270825c1 | ||
![]() |
1e94f0a094 | ||
![]() |
e39d2567ea | ||
![]() |
949136c92a | ||
![]() |
9f456a9b19 | ||
![]() |
4cf6ba25ca | ||
![]() |
093f971896 | ||
![]() |
df38a9da71 | ||
![]() |
813814c54a | ||
![]() |
68cb32f375 | ||
![]() |
93c9590b0f | ||
![]() |
619d979c39 | ||
![]() |
c30faad838 | ||
![]() |
bea0de4980 | ||
![]() |
ef5a490415 | ||
![]() |
fa404285be | ||
![]() |
0e526258ff | ||
![]() |
56d2fb9a3b | ||
![]() |
7c82690852 | ||
![]() |
62acc17e42 | ||
![]() |
9fbe5895b7 | ||
![]() |
6bbe0f07d4 | ||
![]() |
bd3e0b9336 | ||
![]() |
699debdaca | ||
![]() |
70eba568af | ||
![]() |
bb7560e441 | ||
![]() |
43c0cac52f | ||
![]() |
4b4aa148a9 | ||
![]() |
c9c90c4e7f | ||
![]() |
99093e9a4c | ||
![]() |
2cf33d635d | ||
![]() |
d6abaf846e | ||
![]() |
4b88131977 | ||
![]() |
4520f46a57 | ||
![]() |
348d47076a | ||
![]() |
6e7b90a184 | ||
![]() |
28d7a7a6d2 | ||
![]() |
da13b5dbf2 | ||
![]() |
a60710e3bb | ||
![]() |
7d2a2b9983 | ||
![]() |
749df5dacd | ||
![]() |
af88b7c807 | ||
![]() |
4091687733 | ||
![]() |
cfb0a3ba2a | ||
![]() |
6c4d082f35 | ||
![]() |
262185046a | ||
![]() |
da9d00be7d | ||
![]() |
454abc388b | ||
![]() |
3e9174deed | ||
![]() |
4df1047b07 | ||
![]() |
60f69feaff | ||
![]() |
5df426380d | ||
![]() |
976c299657 | ||
![]() |
18ab6b51fd | ||
![]() |
4be8bd4d18 | ||
![]() |
075bc4a6d5 | ||
![]() |
1c61feb368 | ||
![]() |
d32b788988 | ||
![]() |
7565ea2787 | ||
![]() |
9275975b2c | ||
![]() |
b3e0d5ba58 | ||
![]() |
841dee94c6 | ||
![]() |
71638191ee | ||
![]() |
9d6851cbbd | ||
![]() |
d633d05803 | ||
![]() |
45d7879d7b | ||
![]() |
4a8375355c | ||
![]() |
d3ebd763a2 | ||
![]() |
b7f69238a1 | ||
![]() |
118a9f224e | ||
![]() |
a44dc8df37 | ||
![]() |
abf19aad74 | ||
![]() |
d73127b175 | ||
![]() |
00f4242fa4 | ||
![]() |
f6a4510659 | ||
![]() |
33215424d8 | ||
![]() |
6094bc9210 | ||
![]() |
a8cd9b3aa9 | ||
![]() |
a189dec1c8 | ||
![]() |
858216796a | ||
![]() |
f24342f117 | ||
![]() |
50b55a77de | ||
![]() |
fdf167db11 | ||
![]() |
a4f8bd4ee0 | ||
![]() |
3e4c12cf56 | ||
![]() |
03c39e692a | ||
![]() |
ab63b0e970 | ||
![]() |
6ea42a35a9 | ||
![]() |
d366dfc72b | ||
![]() |
85042fbe25 | ||
![]() |
23e5188422 | ||
![]() |
93ee0c8798 | ||
![]() |
aa88486f59 | ||
![]() |
1d9c441038 | ||
![]() |
928c56bda2 | ||
![]() |
bc6f37eecc | ||
![]() |
ffebff8cab | ||
![]() |
6d6bd89d6b | ||
![]() |
0a64a7e5d4 | ||
![]() |
586488af48 | ||
![]() |
7b9a45f1a8 | ||
![]() |
4ff70aefac | ||
![]() |
d63b5d7014 | ||
![]() |
ab5f6bf901 | ||
![]() |
04088b34a2 | ||
![]() |
3edcd2004e | ||
![]() |
7bd52d0245 | ||
![]() |
1df65940b9 | ||
![]() |
d9ace35c3e | ||
![]() |
1fe92cee6f | ||
![]() |
267868c3b0 | ||
![]() |
6d27eb7f64 | ||
![]() |
2e10fa494f | ||
![]() |
039be65a89 | ||
![]() |
570ecd9987 | ||
![]() |
a575180475 | ||
![]() |
07d1a20f3d | ||
![]() |
76491cbb31 | ||
![]() |
bf7d6ddcb2 | ||
![]() |
44b969e0b6 | ||
![]() |
176e470497 | ||
![]() |
646a10d9bf | ||
![]() |
52137fd64f | ||
![]() |
3ccac8c3b8 | ||
![]() |
0be158afa1 | ||
![]() |
e6942e0122 | ||
![]() |
496b22026f | ||
![]() |
bb2df02dff | ||
![]() |
4c850ecc31 | ||
![]() |
da9c6f6e23 | ||
![]() |
58ba0b0b4e | ||
![]() |
1d0b87246a | ||
![]() |
920b60da19 | ||
![]() |
523e66294b | ||
![]() |
23f8f35098 | ||
![]() |
8d210b5e37 | ||
![]() |
3c6c0e6700 | ||
![]() |
01344c451f | ||
![]() |
2c42c79482 | ||
![]() |
75c2cfe7bf | ||
![]() |
6c6eeb3f28 | ||
![]() |
31053e0cd0 | ||
![]() |
aad9aced18 | ||
![]() |
dd2c9eeafe | ||
![]() |
740d76bc42 | ||
![]() |
45f4f5afd9 | ||
![]() |
e875de3e98 | ||
![]() |
fd7786633d | ||
![]() |
bce9cfa39a | ||
![]() |
ff3d66a661 | ||
![]() |
006d28abd5 | ||
![]() |
59b1e63bdf | ||
![]() |
eab74ef06b | ||
![]() |
89837de9b0 | ||
![]() |
b245931c79 | ||
![]() |
fd5e42698c | ||
![]() |
c75512ba6e | ||
![]() |
a22e7aa0b1 | ||
![]() |
020dd97f99 | ||
![]() |
e9882d9702 | ||
![]() |
fd4a27dbf2 | ||
![]() |
9c63e31da6 | ||
![]() |
c91f809eba | ||
![]() |
a54eaf5371 | ||
![]() |
8032bd4bb9 | ||
![]() |
ea1beec2f7 | ||
![]() |
05f2f6820e | ||
![]() |
0f5f15a5ce | ||
![]() |
14ac37e8a5 | ||
![]() |
1fae89cbb6 | ||
![]() |
8b4008798f | ||
![]() |
fd4faf59b8 | ||
![]() |
109891d668 | ||
![]() |
bdea796121 | ||
![]() |
c8813c05c9 | ||
![]() |
1cff08ce5d | ||
![]() |
a868118f6f | ||
![]() |
e5c62f5750 | ||
![]() |
4084e8790b | ||
![]() |
8d931dd773 | ||
![]() |
25d6366297 | ||
![]() |
08cd5b81d1 | ||
![]() |
5d3a8a5b1a | ||
![]() |
79b84da4b8 | ||
![]() |
68b07c5913 | ||
![]() |
553db9124d | ||
![]() |
b495f37299 | ||
![]() |
1915547594 | ||
![]() |
03de29164a | ||
![]() |
86d8b50547 | ||
![]() |
7b04386162 | ||
![]() |
07bfdf3e4d | ||
![]() |
d510224e2a | ||
![]() |
e658f9297d | ||
![]() |
2b502e9a0f | ||
![]() |
59141f9bbe | ||
![]() |
3af66b72f2 | ||
![]() |
422c24bd68 | ||
![]() |
f0f87c8eb9 | ||
![]() |
80dad54119 | ||
![]() |
56a76df28e | ||
![]() |
ee2c801fe0 | ||
![]() |
fc314cc248 | ||
![]() |
fe231a4c80 | ||
![]() |
2e2bbe0a7f | ||
![]() |
857e6e8345 | ||
![]() |
3402981ada | ||
![]() |
f401e577e5 | ||
![]() |
0241a50c6f | ||
![]() |
2a2e1236fc | ||
![]() |
9b170f2b4f | ||
![]() |
51e9ff59de | ||
![]() |
2977dbcded | ||
![]() |
ac60b51035 | ||
![]() |
4c2f33a089 | ||
![]() |
3b071116ac | ||
![]() |
a9f265a591 | ||
![]() |
5b62fc8103 | ||
![]() |
0598f5f89a | ||
![]() |
f723427b8b | ||
![]() |
f69a004c1c | ||
![]() |
1134b18a8b | ||
![]() |
2e4aa507f7 | ||
![]() |
5fb96cdcf4 | ||
![]() |
e8cba3524e | ||
![]() |
7e6b5363f1 | ||
![]() |
29457a1d28 | ||
![]() |
731455f164 | ||
![]() |
b01a8cace6 | ||
![]() |
72db5b4fac | ||
![]() |
ddfd42994e | ||
![]() |
2a9ff9c5ef | ||
![]() |
6d49f05356 | ||
![]() |
85a5e62e36 | ||
![]() |
e67965a381 | ||
![]() |
ec4723096f | ||
![]() |
762b678d24 | ||
![]() |
38fcc57bbf | ||
![]() |
c8c57c74cc | ||
![]() |
0784448c69 | ||
![]() |
de0064af47 | ||
![]() |
baae1fc84f | ||
![]() |
2ab999f4ca | ||
![]() |
c9f390d6e0 | ||
![]() |
af05922ecc | ||
![]() |
299edbf3ab | ||
![]() |
c8abed9d48 | ||
![]() |
3622c49ce1 | ||
![]() |
0462e9a7d9 | ||
![]() |
c3a6091908 | ||
![]() |
ab5fedda0b | ||
![]() |
ba70269398 | ||
![]() |
77fd5fa7de | ||
![]() |
ab74290fe3 | ||
![]() |
3aad9d8166 | ||
![]() |
572e078d87 | ||
![]() |
ee4548230b | ||
![]() |
96b93bd876 | ||
![]() |
927f69fe30 | ||
![]() |
7e9ad5927a | ||
![]() |
6d6b07865e | ||
![]() |
376e7977f0 | ||
![]() |
83ae66daea | ||
![]() |
89e0be0099 | ||
![]() |
ef40c1212e | ||
![]() |
3a2a2a4ffa | ||
![]() |
9592a69986 | ||
![]() |
89be07e1f2 | ||
![]() |
c61c3ae0e9 | ||
![]() |
817350c8c5 | ||
![]() |
3603b7c82b | ||
![]() |
5743c72cca | ||
![]() |
4cdd66ceff | ||
![]() |
d3947d2cfa | ||
![]() |
07718b994a | ||
![]() |
ef9d463bd7 | ||
![]() |
8745c7884e | ||
![]() |
b6965105b7 | ||
![]() |
3d269fe8be | ||
![]() |
be5f00aa1a | ||
![]() |
59ba350f34 | ||
![]() |
803c5377a6 | ||
![]() |
7c12bf7fa1 | ||
![]() |
ca35a9681f | ||
![]() |
9fe5f37337 | ||
![]() |
0742901cd2 | ||
![]() |
5e4d2dedbe | ||
![]() |
411ea56a3e | ||
![]() |
cda57dd4b4 | ||
![]() |
4351de503f | ||
![]() |
6339ba6bfb | ||
![]() |
ef6677f43d | ||
![]() |
a7824af5a8 | ||
![]() |
1eb7d7b7a8 | ||
![]() |
11c33d4447 | ||
![]() |
b8a3cc8b60 | ||
![]() |
27c688252d | ||
![]() |
3e2afd4b1d | ||
![]() |
f45b0686d2 | ||
![]() |
1f3f881f81 | ||
![]() |
ceb51bb14f | ||
![]() |
3e22573d8d | ||
![]() |
79418a3767 | ||
![]() |
40d4683de1 | ||
![]() |
79e5b54ec7 | ||
![]() |
bd81923f2f | ||
![]() |
69560b8ad7 | ||
![]() |
dc413e7b73 | ||
![]() |
7fc00c446b | ||
![]() |
2efc423cf8 | ||
![]() |
8ec3086cdd | ||
![]() |
5fc7079023 | ||
![]() |
bfbd254be7 | ||
![]() |
f8ea43466c | ||
![]() |
75ab1fa570 | ||
![]() |
bf4a46d57c | ||
![]() |
1046dd5eda | ||
![]() |
f9e32a119a | ||
![]() |
dbb8b8a439 | ||
![]() |
2a65c3dc8f | ||
![]() |
f17ec9e9d7 | ||
![]() |
675d6d8328 | ||
![]() |
6dc9ccad75 | ||
![]() |
6add02702b | ||
![]() |
958d6377e3 | ||
![]() |
9954154ca2 | ||
![]() |
4ecbf8c12c | ||
![]() |
fc8a3c5fb4 | ||
![]() |
01e7dff1a0 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -16,3 +16,4 @@ chromeos/** binary
|
||||
*.exe binary
|
||||
*.apk binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -3,9 +3,7 @@ out
|
||||
*.jks
|
||||
*.apk
|
||||
config.prop
|
||||
|
||||
# Manually dumped jars
|
||||
snet/libs
|
||||
update.sh
|
||||
|
||||
# Built binaries
|
||||
native/out
|
||||
@@ -17,4 +15,3 @@ native/out
|
||||
/.idea
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
|
82
README.MD
82
README.MD
@@ -1,41 +1,75 @@
|
||||
# Magisk
|
||||
[Downloads](https://github.com/topjohnwu/Magisk/releases) | [Documentation](https://topjohnwu.github.io/Magisk/) | [XDA Thread](https://forum.xda-developers.com/apps/magisk/official-magisk-v7-universal-systemless-t3473445)
|
||||
|
||||
[Downloads](https://github.com/topjohnwu/Magisk/releases) \| [Documentation](https://topjohnwu.github.io/Magisk/) \| [XDA Thread](https://forum.xda-developers.com/apps/magisk/official-magisk-v7-universal-systemless-t3473445)
|
||||
|
||||
## Introduction
|
||||
Magisk is a suite of open source tools for customizing Android, supporting devices higher than Android 5.0 (API 21). It covers the fundamental parts for Android customization: root, boot scripts, SELinux patches, AVB2.0 / dm-verity / forceencrypt removals etc.
|
||||
|
||||
Magisk is a suite of open source tools for customizing Android, supporting devices higher than Android 4.2 (API 17). It covers the fundamental parts for Android customization: root, boot scripts, SELinux patches, AVB2.0 / dm-verity / forceencrypt removals etc.
|
||||
|
||||
Furthermore, Magisk provides a **Systemless Interface** to alter the system (or vendor) arbitrarily while the actual partitions stay completely intact. With its systemless nature along with several other hacks, Magisk can hide modifications from nearly any system integrity verifications used in banking apps, corporation monitoring apps, game cheat detections, and most importantly [Google's SafetyNet API](https://developer.android.com/training/safetynet/index.html).
|
||||
|
||||
## Bug Reports
|
||||
|
||||
**Make sure to install the latest [Canary Build](https://forum.xda-developers.com/apps/magisk/dev-magisk-canary-channel-bleeding-edge-t3839337) before reporting any bugs!** **DO NOT** report bugs that is already fixed upstream. Follow the instructions in the [Canary Channel XDA Thread](https://forum.xda-developers.com/apps/magisk/dev-magisk-canary-channel-bleeding-edge-t3839337), and report a bug either by opening an issue on GitHub or directly in the thread.
|
||||
|
||||
## Building Environment Requirements
|
||||
1. Python 3.5+: run `build.py` script
|
||||
2. Java Development Kit (JDK) 8: Compile Magisk Manager and sign zips
|
||||
3. Latest Android SDK: set `ANDROID_HOME` environment variable to the path to Android SDK
|
||||
4. Android NDK: Install NDK along with SDK (`$ANDROID_HOME/ndk-bundle`), or optionally specify a custom path `ANDROID_NDK_HOME`
|
||||
5. (Windows Only) Python package Colorama: Install with `pip install colorama`, used for ANSI color codes
|
||||
|
||||
- Python 3: run `build.py` script
|
||||
- Java Development Kit (JDK) 8: Compile Magisk Manager and sign zips
|
||||
- Latest Android SDK: set `ANDROID_HOME` environment variable to the path to Android SDK
|
||||
- Android NDK: Install NDK along with SDK (`$ANDROID_HOME/ndk-bundle`), or optionally specify a custom path `ANDROID_NDK_HOME`
|
||||
- (Windows Only) Python package Colorama: Install with `pip install colorama`, used for ANSI color codes
|
||||
|
||||
## Building Notes and Instructions
|
||||
1. Clone sources with submodules: `git clone --recurse-submodules https://github.com/topjohnwu/Magisk.git`
|
||||
2. Building is supported on macOS, Linux, and Windows. Official releases are built and tested with [FrankeNDK](https://github.com/topjohnwu/FrankeNDK); point `ANDROID_NDK_HOME` to FrankeNDK if you want to use it for compiling.
|
||||
3. Set configurations in `config.prop`. A sample file `config.prop.sample` is provided as an example.
|
||||
4. Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h`
|
||||
5. By default, `build.py` build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (via the `-r, --release` flag), you need a Java Keystore file `release-key.jks` (only `JKS` format is supported) to sign APKs and zips. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
|
||||
|
||||
- Clone sources with submodules: `git clone --recurse-submodules https://github.com/topjohnwu/Magisk.git`
|
||||
- Building is supported on macOS, Linux, and Windows. Official releases are built and tested with [FrankeNDK](https://github.com/topjohnwu/FrankeNDK); point `ANDROID_NDK_HOME` to FrankeNDK if you want to use it for compiling.
|
||||
- Set configurations in `config.prop`. A sample file `config.prop.sample` is provided as an example.
|
||||
- Run `build.py` with argument `-h` to see the built-in help message. The `-h` option also works for each supported actions, e.g. `./build.py binary -h`
|
||||
- By default, `build.py` build binaries and Magisk Manager in debug mode. If you want to build Magisk Manager in release mode (via the `-r, --release` flag), you need a Java Keystore file `release-key.jks` (only `JKS` format is supported) to sign APKs and zips. For more information, check out [Google's Official Documentation](https://developer.android.com/studio/publish/app-signing.html#signing-manually).
|
||||
|
||||
## Translations
|
||||
|
||||
Default string resources for Magisk Manager are scattered throughout
|
||||
|
||||
- `app/src/main/res/values/strings.xml`
|
||||
- `stub/src/main/res/values/strings.xml`
|
||||
- `shared/src/main/res/values/strings.xml`
|
||||
|
||||
Translate each and place them in the respective locations (`<module>/src/main/res/values-<lang>/strings.xml`).
|
||||
|
||||
## Signature Verification
|
||||
|
||||
Official release zips and APKs are signed with my personal private key. You can verify the key certificate to make sure the binaries you downloaded are not manipulated in anyway.
|
||||
|
||||
``` bash
|
||||
# Use the keytool command from JDK to print certificates
|
||||
keytool -printcert -jarfile <APK or Magisk zip>
|
||||
|
||||
# The output should contain the following signature
|
||||
Owner: CN=John Wu, L=Taipei, C=TW
|
||||
Issuer: CN=John Wu, L=Taipei, C=TW
|
||||
Serial number: 50514879
|
||||
Valid from: Sun Aug 14 13:23:44 EDT 2016 until: Tue Jul 21 13:23:44 EDT 2116
|
||||
Certificate fingerprints:
|
||||
MD5: CE:DA:68:C1:E1:74:71:0A:EF:58:89:7D:AE:6E:AB:4F
|
||||
SHA1: DC:0F:2B:61:CB:D7:E9:D3:DB:BE:06:0B:2B:87:0D:46:BB:06:02:11
|
||||
SHA256: B4:CB:83:B4:DA:D9:9F:99:7D:BE:87:2F:01:3A:A1:6C:14:EE:C4:1D:16:70:21:F3:71:F7:E1:33:0F:27:3E:E6
|
||||
Signature algorithm name: SHA256withRSA
|
||||
Version: 3
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
```
|
||||
Magisk, including all git submodules are free software:
|
||||
you can redistribute it and/or modify it under the terms of the
|
||||
GNU General Public License as published by the Free Software Foundation,
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
Magisk, including all git submodules are free software:
|
||||
you can redistribute it and/or modify it under the terms of the
|
||||
GNU General Public License as published by the Free Software Foundation,
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
```
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
1
app/.gitignore
vendored
1
app/.gitignore
vendored
@@ -6,7 +6,6 @@
|
||||
app/release
|
||||
*.hprof
|
||||
.externalNativeBuild/
|
||||
src/full/res/raw/util_functions.sh
|
||||
public.certificate.x509.pem
|
||||
private.key.pk8
|
||||
*.apk
|
||||
|
@@ -1,7 +0,0 @@
|
||||
# Magisk Manager
|
||||
This repo is no longer an independent component. It is merged into the [Magisk Project](https://github.com/topjohnwu/Magisk).
|
||||
|
||||
# Translations
|
||||
The default (English) strings are mainly in `src/full/res/values/strings.xml`; some are scattered in `src/main/res/values/strings.xml` and `src/stub/res/values/strings.xml`.
|
||||
Translations are highly appreciated via pull requests here on Github.
|
||||
Place translated XMLs in the corresponding locale folder.
|
118
app/build.gradle
118
app/build.gradle
@@ -1,90 +1,66 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
def configProps = new Properties()
|
||||
def configPath = project.hasProperty('configPath') ? project.configPath : rootProject.file('config.prop')
|
||||
configProps.load(new FileInputStream(configPath))
|
||||
kapt {
|
||||
correctErrorTypes = true
|
||||
useBuildCache = true
|
||||
mapDiagnosticLocations = true
|
||||
javacOptions {
|
||||
option("-Xmaxerrs", 1000)
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.topjohnwu.magisk"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion rootProject.ext.compileSdkVersion
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
config {
|
||||
storeFile rootProject.file('release-key.jks')
|
||||
storePassword configProps['keyStorePass']
|
||||
keyAlias configProps['keyAlias']
|
||||
keyPassword configProps['keyPass']
|
||||
applicationId 'com.topjohnwu.magisk'
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
versionName configProps['appVersion']
|
||||
versionCode configProps['appVersionCode'] as Integer
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
argument('butterknife.debuggable', 'false')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
// If keystore exists, sign the APK with custom signature
|
||||
if (signingConfigs.config.storeFile.exists())
|
||||
signingConfig signingConfigs.config
|
||||
}
|
||||
release {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.config
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "mode"
|
||||
|
||||
productFlavors {
|
||||
full {
|
||||
versionName configProps['appVersion']
|
||||
versionCode configProps['appVersionCode'] as Integer
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
argument('butterknife.debuggable', 'false')
|
||||
}
|
||||
}
|
||||
}
|
||||
stub {
|
||||
versionCode 1
|
||||
versionName "stub"
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
dexOptions {
|
||||
preDexLibraries true
|
||||
javaMaxHeapSize "2g"
|
||||
}
|
||||
lintOptions {
|
||||
disable 'MissingTranslation'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
fullImplementation project(':utils')
|
||||
implementation "androidx.core:core:${rootProject.ext.androidXVersion}"
|
||||
fullImplementation "androidx.preference:preference:${rootProject.ext.androidXVersion}"
|
||||
fullImplementation "androidx.recyclerview:recyclerview:${rootProject.ext.androidXVersion}"
|
||||
fullImplementation "androidx.cardview:cardview:${rootProject.ext.androidXVersion}"
|
||||
fullImplementation "com.google.android.material:material:${rootProject.ext.androidXVersion}"
|
||||
fullImplementation 'com.github.topjohnwu:libsu:2.0.2'
|
||||
fullImplementation 'com.atlassian.commonmark:commonmark:0.11.0'
|
||||
fullImplementation 'org.kamranzafar:jtar:2.3'
|
||||
implementation project(':net')
|
||||
implementation project(':shared')
|
||||
implementation project(':signing')
|
||||
implementation 'com.github.topjohnwu:jtar:1.0.0'
|
||||
implementation 'net.sourceforge.streamsupport:android-retrostreams:1.7.0'
|
||||
implementation 'com.github.sevar83:indeterminate-checkbox:1.0.5'
|
||||
|
||||
def butterKnifeVersion = '9.0.0-rc1'
|
||||
if (properties.containsKey('android.injected.invoked.from.ide')) {
|
||||
fullImplementation "com.jakewharton:butterknife-reflect:${butterKnifeVersion}"
|
||||
} else {
|
||||
fullImplementation "com.jakewharton:butterknife-runtime:${butterKnifeVersion}"
|
||||
fullAnnotationProcessor "com.jakewharton:butterknife-compiler:${butterKnifeVersion}"
|
||||
}
|
||||
def markwonVersion = '3.0.0'
|
||||
implementation "ru.noties.markwon:core:${markwonVersion}"
|
||||
implementation "ru.noties.markwon:html:${markwonVersion}"
|
||||
implementation "ru.noties.markwon:image-svg:${markwonVersion}"
|
||||
|
||||
def androidXVersion = "1.0.0"
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
implementation "androidx.preference:preference:${androidXVersion}"
|
||||
implementation "androidx.recyclerview:recyclerview:${androidXVersion}"
|
||||
implementation "androidx.cardview:cardview:${androidXVersion}"
|
||||
implementation "com.google.android.material:material:${androidXVersion}"
|
||||
implementation 'androidx.work:work-runtime:2.0.1'
|
||||
implementation 'androidx.transition:transition:1.1.0-beta01'
|
||||
|
||||
def libsuVersion = '2.5.0'
|
||||
implementation "com.github.topjohnwu.libsu:core:${libsuVersion}"
|
||||
implementation "com.github.topjohnwu.libsu:io:${libsuVersion}"
|
||||
|
||||
def butterKnifeVersion = '10.1.0'
|
||||
implementation "com.jakewharton:butterknife-runtime:${butterKnifeVersion}"
|
||||
kapt "com.jakewharton:butterknife-compiler:${butterKnifeVersion}"
|
||||
}
|
||||
|
29
app/proguard-rules.pro
vendored
29
app/proguard-rules.pro
vendored
@@ -17,13 +17,29 @@
|
||||
#}
|
||||
|
||||
# BouncyCastle
|
||||
-keep class org.bouncycastle.jcajce.provider.asymmetric.rsa.**SHA1** { *; }
|
||||
-keep class org.bouncycastle.jcajce.provider.asymmetric.RSA** { *; }
|
||||
-keep class org.bouncycastle.jcajce.provider.digest.SHA1** { *; }
|
||||
-keep,allowoptimization class org.bouncycastle.jcajce.provider.asymmetric.rsa.**SHA1** { *; }
|
||||
-keep,allowoptimization class org.bouncycastle.jcajce.provider.asymmetric.RSA** { *; }
|
||||
-keep,allowoptimization class org.bouncycastle.jcajce.provider.digest.SHA1** { *; }
|
||||
-dontwarn javax.naming.**
|
||||
|
||||
# Snet extention
|
||||
# Snet
|
||||
-keepclassmembers class com.topjohnwu.magisk.utils.ISafetyNetHelper { *; }
|
||||
-keep,allowobfuscation interface com.topjohnwu.magisk.utils.ISafetyNetHelper$Callback
|
||||
-keepclassmembers class * implements com.topjohnwu.magisk.utils.ISafetyNetHelper$Callback {
|
||||
void onResponse(int);
|
||||
}
|
||||
|
||||
# DelegateWorker
|
||||
-keep,allowobfuscation class * extends com.topjohnwu.magisk.model.worker.DelegateWorker
|
||||
|
||||
# BootSigner
|
||||
-keepclassmembers class com.topjohnwu.signing.BootSigner { *; }
|
||||
|
||||
# SVG
|
||||
-dontwarn com.caverock.androidsvg.SVGAndroidRenderer
|
||||
|
||||
# RetroStreams
|
||||
-dontwarn java9.**
|
||||
|
||||
# Strip logging
|
||||
-assumenosideeffects class com.topjohnwu.magisk.utils.Logger {
|
||||
@@ -33,3 +49,8 @@
|
||||
# Excessive obfuscation
|
||||
-repackageclasses 'a'
|
||||
-allowaccessmodification
|
||||
|
||||
# QOL
|
||||
-dontnote **
|
||||
-dontwarn com.caverock.androidsvg.**
|
||||
-dontwarn ru.noties.markwon.**
|
||||
|
@@ -1,105 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.topjohnwu.magisk">
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:name="a.q"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
|
||||
<!-- Activities -->
|
||||
|
||||
<activity
|
||||
android:name="a.b"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="true" />
|
||||
<activity
|
||||
android:name="a.c"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:exported="true"
|
||||
android:theme="@style/SplashTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="a.d"
|
||||
android:theme="@style/AppTheme.StatusBar" />
|
||||
<activity
|
||||
android:name="a.e"
|
||||
android:theme="@style/AppTheme.StatusBar"/>
|
||||
<activity
|
||||
android:name="a.f"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:screenOrientation="nosensor"
|
||||
android:theme="@style/AppTheme.StatusBar" />
|
||||
<activity
|
||||
android:name="a.g"
|
||||
android:theme="@style/AppTheme.Translucent" />
|
||||
|
||||
<!-- Superuser -->
|
||||
|
||||
<activity
|
||||
android:name="a.p"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleTask"
|
||||
android:taskAffinity="internal.superuser"
|
||||
android:theme="@style/SuRequest" />
|
||||
|
||||
<activity
|
||||
android:name=".superuser.RequestActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:launchMode="singleTask"
|
||||
android:taskAffinity="internal.superuser"
|
||||
android:theme="@style/AppTheme.Translucent" />
|
||||
|
||||
<receiver android:name=".superuser.SuReceiver" />
|
||||
|
||||
<!-- Receiver -->
|
||||
|
||||
<receiver android:name="a.h">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name="a.i">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||
<action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
|
||||
<data android:scheme="package" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name="a.j" />
|
||||
<receiver android:name="a.k" />
|
||||
<receiver android:name="a.l">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.LOCALE_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- Service -->
|
||||
|
||||
<service
|
||||
android:name="a.m"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
<service
|
||||
android:name="a.n"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
<!-- Hardcode GMS version -->
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="12451000" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
@@ -1,10 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.utils.BootSigner;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
@Keep
|
||||
public class a extends BootSigner {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.AboutActivity;
|
||||
|
||||
public class d extends AboutActivity {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.DonationActivity;
|
||||
|
||||
public class e extends DonationActivity {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.receivers.BootReceiver;
|
||||
|
||||
public class h extends BootReceiver {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.receivers.PackageReceiver;
|
||||
|
||||
public class i extends PackageReceiver {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.receivers.ManagerUpdate;
|
||||
|
||||
public class j extends ManagerUpdate {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.receivers.RebootReceiver;
|
||||
|
||||
public class k extends RebootReceiver {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.receivers.ShortcutReceiver;
|
||||
|
||||
public class l extends ShortcutReceiver {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.services.OnBootService;
|
||||
|
||||
public class m extends OnBootService {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||
|
||||
public class n extends UpdateCheckService {
|
||||
/* stub */
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
package a;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||
|
||||
public class o extends AboutCardRow {
|
||||
/* stub */
|
||||
|
||||
public o(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public o(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public o(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.SuRequestActivity;
|
||||
|
||||
public class p extends SuRequestActivity {
|
||||
/* stub */
|
||||
}
|
@@ -1,7 +0,0 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
|
||||
public class q extends MagiskManager {
|
||||
/* stub */
|
||||
}
|
@@ -1,72 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||
import com.topjohnwu.magisk.components.BaseActivity;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import butterknife.BindView;
|
||||
|
||||
public class AboutActivity extends BaseActivity {
|
||||
|
||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||
@BindView(R.id.app_version_info) AboutCardRow appVersionInfo;
|
||||
@BindView(R.id.app_changelog) AboutCardRow appChangelog;
|
||||
@BindView(R.id.app_translators) AboutCardRow appTranslators;
|
||||
@BindView(R.id.app_source_code) AboutCardRow appSourceCode;
|
||||
@BindView(R.id.support_thread) AboutCardRow supportThread;
|
||||
@BindView(R.id.follow_twitter) AboutCardRow twitter;
|
||||
|
||||
@Override
|
||||
public int getDarkTheme() {
|
||||
return R.style.AppTheme_StatusBar_Dark;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_about);
|
||||
new AboutActivity_ViewBinding(this);
|
||||
|
||||
setSupportActionBar(toolbar);
|
||||
toolbar.setNavigationOnClickListener(view -> finish());
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setTitle(R.string.about);
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
appVersionInfo.setSummary(String.format(Locale.US, "%s (%d) (%s)",
|
||||
BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, getPackageName()));
|
||||
|
||||
appChangelog.setOnClickListener(v -> {
|
||||
new MarkDownWindow(this, getString(R.string.app_changelog),
|
||||
getResources().openRawResource(R.raw.changelog)).exec();
|
||||
});
|
||||
|
||||
String translators = getString(R.string.translators);
|
||||
if (TextUtils.isEmpty(translators)) {
|
||||
appTranslators.setVisibility(View.GONE);
|
||||
} else {
|
||||
appTranslators.setSummary(translators);
|
||||
}
|
||||
|
||||
appSourceCode.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.SOURCE_CODE_URL)));
|
||||
supportThread.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.XDA_THREAD)));
|
||||
twitter.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.TWITTER_URL)));
|
||||
|
||||
setFloating();
|
||||
}
|
||||
|
||||
}
|
@@ -1,150 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.os.Process;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Const {
|
||||
|
||||
public static final String DEBUG_TAG = "MagiskManager";
|
||||
public static final String ORIG_PKG_NAME = BuildConfig.APPLICATION_ID;
|
||||
public static final String MAGISKHIDE_PROP = "persist.magisk.hide";
|
||||
|
||||
// APK content
|
||||
public static final String ANDROID_MANIFEST = "AndroidManifest.xml";
|
||||
|
||||
public static final String SU_KEYSTORE_KEY = "su_key";
|
||||
|
||||
// Paths
|
||||
public static File MAGISK_PATH;
|
||||
public static File MAGISK_DISABLE_FILE;
|
||||
public static File MAGISK_HOST_FILE;
|
||||
|
||||
static {
|
||||
/* Prevent crashing on unrooted devices */
|
||||
MAGISK_PATH = MAGISK_DISABLE_FILE = MAGISK_HOST_FILE = new File("xxx");
|
||||
}
|
||||
|
||||
public static final String BUSYBOX_PATH = "/sbin/.core/busybox";
|
||||
public static final String TMP_FOLDER_PATH = "/dev/tmp";
|
||||
public static final String MAGISK_LOG = "/cache/magisk.log";
|
||||
public static final String MANAGER_CONFIGS = ".tmp.magisk.config";
|
||||
|
||||
// Versions
|
||||
public static final int UPDATE_SERVICE_VER = 1;
|
||||
|
||||
public static int MIN_MODULE_VER() {
|
||||
return Data.magiskVersionCode >= MAGISK_VER.REMOVE_LEGACY_LINK ? 1500 : 1400;
|
||||
}
|
||||
|
||||
/* A list of apps that should not be shown as hide-able */
|
||||
public static final List<String> HIDE_BLACKLIST = Arrays.asList(
|
||||
Data.MM().getPackageName(),
|
||||
"com.google.android.gms"
|
||||
);
|
||||
|
||||
public static final int USER_ID = Process.myUid() / 100000;
|
||||
|
||||
public static final class MAGISK_VER {
|
||||
public static final int REMOVE_LEGACY_LINK = 1630;
|
||||
public static final int SEPOL_REFACTOR = 1640;
|
||||
public static final int FIX_ENV = 1650;
|
||||
public static final int DBVER_SIX = 17000;
|
||||
}
|
||||
|
||||
public static class ID {
|
||||
public static final int UPDATE_SERVICE_ID = 1;
|
||||
public static final int FETCH_ZIP = 2;
|
||||
public static final int SELECT_BOOT = 3;
|
||||
public static final int ONBOOT_SERVICE_ID = 6;
|
||||
|
||||
// notifications
|
||||
public static final int MAGISK_UPDATE_NOTIFICATION_ID = 4;
|
||||
public static final int APK_UPDATE_NOTIFICATION_ID = 5;
|
||||
public static final int DTBO_NOTIFICATION_ID = 7;
|
||||
public static final String NOTIFICATION_CHANNEL = "magisk_notification";
|
||||
}
|
||||
|
||||
public static class Url {
|
||||
public static final String STABLE_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/stable.json";
|
||||
public static final String BETA_URL = "https://raw.githubusercontent.com/topjohnwu/magisk_files/master/beta.json";
|
||||
public static final String REPO_URL = "https://api.github.com/users/Magisk-Modules-Repo/repos?per_page=100&sort=pushed&page=%d";
|
||||
public static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s";
|
||||
public static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip";
|
||||
public static final String PAYPAL_URL = "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=CC7FZ7526MNGG";
|
||||
public static final String PATREON_URL = "https://www.patreon.com/topjohnwu";
|
||||
public static final String TWITTER_URL = "https://twitter.com/topjohnwu";
|
||||
public static final String XDA_THREAD = "http://forum.xda-developers.com/showthread.php?t=3432382";
|
||||
public static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk";
|
||||
}
|
||||
|
||||
|
||||
public static class Key {
|
||||
// su
|
||||
public static final String ROOT_ACCESS = "root_access";
|
||||
public static final String SU_MULTIUSER_MODE = "multiuser_mode";
|
||||
public static final String SU_MNT_NS = "mnt_ns";
|
||||
public static final String SU_MANAGER = "requester";
|
||||
public static final String SU_REQUEST_TIMEOUT = "su_request_timeout";
|
||||
public static final String SU_AUTO_RESPONSE = "su_auto_response";
|
||||
public static final String SU_NOTIFICATION = "su_notification";
|
||||
public static final String SU_REAUTH = "su_reauth";
|
||||
public static final String SU_FINGERPRINT = "su_fingerprint";
|
||||
|
||||
// intents
|
||||
public static final String OPEN_SECTION = "section";
|
||||
public static final String INTENT_SET_FILENAME = "filename";
|
||||
public static final String INTENT_SET_LINK = "link";
|
||||
public static final String FLASH_ACTION = "action";
|
||||
public static final String FLASH_SET_BOOT = "boot";
|
||||
|
||||
// others
|
||||
public static final String CHECK_UPDATES = "check_update";
|
||||
public static final String UPDATE_CHANNEL = "update_channel";
|
||||
public static final String CUSTOM_CHANNEL = "custom_channel";
|
||||
public static final String BOOT_FORMAT = "boot_format";
|
||||
public static final String UPDATE_SERVICE_VER = "update_service_version";
|
||||
public static final String APP_VER = "app_version";
|
||||
public static final String MAGISKHIDE = "magiskhide";
|
||||
public static final String HOSTS = "hosts";
|
||||
public static final String COREONLY = "disable";
|
||||
public static final String LOCALE = "locale";
|
||||
public static final String DARK_THEME = "dark_theme";
|
||||
public static final String ETAG_KEY = "ETag";
|
||||
public static final String LINK_KEY = "Link";
|
||||
public static final String IF_NONE_MATCH = "If-None-Match";
|
||||
public static final String REPO_ORDER = "repo_order";
|
||||
}
|
||||
|
||||
|
||||
public static class Value {
|
||||
public static final int STABLE_CHANNEL = 0;
|
||||
public static final int BETA_CHANNEL = 1;
|
||||
public static final int CUSTOM_CHANNEL = 2;
|
||||
public static final int ROOT_ACCESS_DISABLED = 0;
|
||||
public static final int ROOT_ACCESS_APPS_ONLY = 1;
|
||||
public static final int ROOT_ACCESS_ADB_ONLY = 2;
|
||||
public static final int ROOT_ACCESS_APPS_AND_ADB = 3;
|
||||
public static final int MULTIUSER_MODE_OWNER_ONLY = 0;
|
||||
public static final int MULTIUSER_MODE_OWNER_MANAGED = 1;
|
||||
public static final int MULTIUSER_MODE_USER = 2;
|
||||
public static final int NAMESPACE_MODE_GLOBAL = 0;
|
||||
public static final int NAMESPACE_MODE_REQUESTER = 1;
|
||||
public static final int NAMESPACE_MODE_ISOLATE = 2;
|
||||
public static final int NO_NOTIFICATION = 0;
|
||||
public static final int NOTIFICATION_TOAST = 1;
|
||||
public static final int SU_PROMPT = 0;
|
||||
public static final int SU_AUTO_DENY = 1;
|
||||
public static final int SU_AUTO_ALLOW = 2;
|
||||
public static final String FLASH_ZIP = "flash";
|
||||
public static final String PATCH_BOOT = "patch";
|
||||
public static final String FLASH_MAGISK = "magisk";
|
||||
public static final String FLASH_INACTIVE_SLOT = "slot";
|
||||
public static final String UNINSTALL = "uninstall";
|
||||
public static final int[] timeoutList = {0, -1, 10, 20, 30, 60};
|
||||
public static final int ORDER_NAME = 0;
|
||||
public static final int ORDER_DATE = 1;
|
||||
}
|
||||
}
|
@@ -1,217 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||
import com.topjohnwu.magisk.receivers.BootReceiver;
|
||||
import com.topjohnwu.magisk.receivers.ManagerUpdate;
|
||||
import com.topjohnwu.magisk.receivers.PackageReceiver;
|
||||
import com.topjohnwu.magisk.receivers.RebootReceiver;
|
||||
import com.topjohnwu.magisk.receivers.ShortcutReceiver;
|
||||
import com.topjohnwu.magisk.services.OnBootService;
|
||||
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
import com.topjohnwu.superuser.io.SuFileInputStream;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Data {
|
||||
// Global app instance
|
||||
public static WeakReference<MagiskManager> weakApp;
|
||||
public static Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
public static Map<Class, Class> classMap = new HashMap<>();
|
||||
|
||||
// Current status
|
||||
public static String magiskVersionString;
|
||||
public static int magiskVersionCode = -1;
|
||||
public static boolean magiskHide;
|
||||
|
||||
// Update Info
|
||||
public static String remoteMagiskVersionString;
|
||||
public static int remoteMagiskVersionCode = -1;
|
||||
public static String magiskLink;
|
||||
public static String magiskNoteLink;
|
||||
public static String magiskMD5;
|
||||
public static String remoteManagerVersionString;
|
||||
public static int remoteManagerVersionCode = -1;
|
||||
public static String managerLink;
|
||||
public static String managerNoteLink;
|
||||
public static String uninstallerLink;
|
||||
public static int snetVersionCode;
|
||||
public static String snetLink;
|
||||
|
||||
// Install flags
|
||||
public static boolean keepVerity = false;
|
||||
public static boolean keepEnc = false;
|
||||
|
||||
// Configs
|
||||
public static boolean isDarkTheme;
|
||||
public static int suRequestTimeout;
|
||||
public static int suLogTimeout = 14;
|
||||
public static int suAccessState;
|
||||
public static boolean suFingerprint;
|
||||
public static int multiuserMode;
|
||||
public static int suResponseType;
|
||||
public static int suNotificationType;
|
||||
public static int suNamespaceMode;
|
||||
public static int updateChannel;
|
||||
public static int repoOrder;
|
||||
|
||||
static {
|
||||
classMap.put(MagiskManager.class, a.q.class);
|
||||
classMap.put(MainActivity.class, a.b.class);
|
||||
classMap.put(SplashActivity.class, a.c.class);
|
||||
classMap.put(AboutActivity.class, a.d.class);
|
||||
classMap.put(DonationActivity.class, a.e.class);
|
||||
classMap.put(FlashActivity.class, a.f.class);
|
||||
classMap.put(NoUIActivity.class, a.g.class);
|
||||
classMap.put(BootReceiver.class, a.h.class);
|
||||
classMap.put(PackageReceiver.class, a.i.class);
|
||||
classMap.put(ManagerUpdate.class, a.j.class);
|
||||
classMap.put(RebootReceiver.class, a.k.class);
|
||||
classMap.put(ShortcutReceiver.class, a.l.class);
|
||||
classMap.put(OnBootService.class, a.m.class);
|
||||
classMap.put(UpdateCheckService.class, a.n.class);
|
||||
classMap.put(AboutCardRow.class, a.o.class);
|
||||
classMap.put(SuRequestActivity.class, a.p.class);
|
||||
|
||||
}
|
||||
|
||||
public static void loadMagiskInfo() {
|
||||
try {
|
||||
magiskVersionString = ShellUtils.fastCmd("magisk -v").split(":")[0];
|
||||
magiskVersionCode = Integer.parseInt(ShellUtils.fastCmd("magisk -V"));
|
||||
String s = ShellUtils.fastCmd(("resetprop -p ") + Const.MAGISKHIDE_PROP);
|
||||
magiskHide = s.isEmpty() || Integer.parseInt(s) != 0;
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
|
||||
public static MagiskManager MM() {
|
||||
return weakApp.get();
|
||||
}
|
||||
|
||||
public static void exportPrefs() {
|
||||
// Flush prefs to disk
|
||||
MagiskManager mm = MM();
|
||||
mm.prefs.edit().commit();
|
||||
File xml = new File(mm.getFilesDir().getParent() + "/shared_prefs",
|
||||
mm.getPackageName() + "_preferences.xml");
|
||||
Shell.su(Utils.fmt("for usr in /data/user/*; do cat %s > ${usr}/%s; done", xml, Const.MANAGER_CONFIGS)).exec();
|
||||
}
|
||||
|
||||
public static void importPrefs() {
|
||||
MagiskManager mm = MM();
|
||||
SuFile config = new SuFile(Utils.fmt("/data/user/%d/%s", Const.USER_ID, Const.MANAGER_CONFIGS));
|
||||
if (config.exists()) {
|
||||
SharedPreferences.Editor editor = mm.prefs.edit();
|
||||
try {
|
||||
SuFileInputStream is = new SuFileInputStream(config);
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
|
||||
parser.setInput(is, "UTF-8");
|
||||
parser.nextTag();
|
||||
parser.require(XmlPullParser.START_TAG, null, "map");
|
||||
while (parser.next() != XmlPullParser.END_TAG) {
|
||||
if (parser.getEventType() != XmlPullParser.START_TAG)
|
||||
continue;
|
||||
String key = parser.getAttributeValue(null, "name");
|
||||
String value = parser.getAttributeValue(null, "value");
|
||||
switch (parser.getName()) {
|
||||
case "string":
|
||||
parser.require(XmlPullParser.START_TAG, null, "string");
|
||||
editor.putString(key, parser.nextText());
|
||||
parser.require(XmlPullParser.END_TAG, null, "string");
|
||||
break;
|
||||
case "boolean":
|
||||
parser.require(XmlPullParser.START_TAG, null, "boolean");
|
||||
editor.putBoolean(key, Boolean.parseBoolean(value));
|
||||
parser.nextTag();
|
||||
parser.require(XmlPullParser.END_TAG, null, "boolean");
|
||||
break;
|
||||
case "int":
|
||||
parser.require(XmlPullParser.START_TAG, null, "int");
|
||||
editor.putInt(key, Integer.parseInt(value));
|
||||
parser.nextTag();
|
||||
parser.require(XmlPullParser.END_TAG, null, "int");
|
||||
break;
|
||||
case "long":
|
||||
parser.require(XmlPullParser.START_TAG, null, "long");
|
||||
editor.putLong(key, Long.parseLong(value));
|
||||
parser.nextTag();
|
||||
parser.require(XmlPullParser.END_TAG, null, "long");
|
||||
break;
|
||||
case "float":
|
||||
parser.require(XmlPullParser.START_TAG, null, "int");
|
||||
editor.putFloat(key, Float.parseFloat(value));
|
||||
parser.nextTag();
|
||||
parser.require(XmlPullParser.END_TAG, null, "int");
|
||||
break;
|
||||
default:
|
||||
parser.next();
|
||||
}
|
||||
}
|
||||
} catch (IOException | XmlPullParserException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
editor.remove(Const.Key.ETAG_KEY);
|
||||
editor.apply();
|
||||
loadConfig();
|
||||
config.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadConfig() {
|
||||
MagiskManager mm = MM();
|
||||
// su
|
||||
suRequestTimeout = Utils.getPrefsInt(mm.prefs, Const.Key.SU_REQUEST_TIMEOUT, Const.Value.timeoutList[2]);
|
||||
suResponseType = Utils.getPrefsInt(mm.prefs, Const.Key.SU_AUTO_RESPONSE, Const.Value.SU_PROMPT);
|
||||
suNotificationType = Utils.getPrefsInt(mm.prefs, Const.Key.SU_NOTIFICATION, Const.Value.NOTIFICATION_TOAST);
|
||||
suAccessState = mm.mDB.getSettings(Const.Key.ROOT_ACCESS, Const.Value.ROOT_ACCESS_APPS_AND_ADB);
|
||||
multiuserMode = mm.mDB.getSettings(Const.Key.SU_MULTIUSER_MODE, Const.Value.MULTIUSER_MODE_OWNER_ONLY);
|
||||
suNamespaceMode = mm.mDB.getSettings(Const.Key.SU_MNT_NS, Const.Value.NAMESPACE_MODE_REQUESTER);
|
||||
suFingerprint = mm.mDB.getSettings(Const.Key.SU_FINGERPRINT, 0) != 0;
|
||||
if (suFingerprint && !FingerprintHelper.canUseFingerprint()) {
|
||||
// User revoked the fingerprint
|
||||
mm.mDB.setSettings(Const.Key.SU_FINGERPRINT, 0);
|
||||
suFingerprint = false;
|
||||
}
|
||||
|
||||
// config
|
||||
isDarkTheme = mm.prefs.getBoolean(Const.Key.DARK_THEME, false);
|
||||
updateChannel = Utils.getPrefsInt(mm.prefs, Const.Key.UPDATE_CHANNEL, Const.Value.STABLE_CHANNEL);
|
||||
repoOrder = mm.prefs.getInt(Const.Key.REPO_ORDER, Const.Value.ORDER_DATE);
|
||||
}
|
||||
|
||||
public static void writeConfig() {
|
||||
MM().prefs.edit()
|
||||
.putBoolean(Const.Key.DARK_THEME, isDarkTheme)
|
||||
.putBoolean(Const.Key.MAGISKHIDE, magiskHide)
|
||||
.putBoolean(Const.Key.HOSTS, Const.MAGISK_HOST_FILE.exists())
|
||||
.putBoolean(Const.Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists())
|
||||
.putBoolean(Const.Key.SU_FINGERPRINT, suFingerprint)
|
||||
.putString(Const.Key.SU_REQUEST_TIMEOUT, String.valueOf(suRequestTimeout))
|
||||
.putString(Const.Key.SU_AUTO_RESPONSE, String.valueOf(suResponseType))
|
||||
.putString(Const.Key.SU_NOTIFICATION, String.valueOf(suNotificationType))
|
||||
.putString(Const.Key.ROOT_ACCESS, String.valueOf(suAccessState))
|
||||
.putString(Const.Key.SU_MULTIUSER_MODE, String.valueOf(multiuserMode))
|
||||
.putString(Const.Key.SU_MNT_NS, String.valueOf(suNamespaceMode))
|
||||
.putString(Const.Key.UPDATE_CHANNEL, String.valueOf(updateChannel))
|
||||
.putInt(Const.Key.UPDATE_SERVICE_VER, Const.UPDATE_SERVICE_VER)
|
||||
.putInt(Const.Key.REPO_ORDER, repoOrder)
|
||||
.apply();
|
||||
}
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.topjohnwu.magisk.components.AboutCardRow;
|
||||
import com.topjohnwu.magisk.components.BaseActivity;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import butterknife.BindView;
|
||||
|
||||
public class DonationActivity extends BaseActivity {
|
||||
|
||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||
@BindView(R.id.paypal) AboutCardRow paypal;
|
||||
@BindView(R.id.patreon) AboutCardRow patreon;
|
||||
|
||||
@Override
|
||||
public int getDarkTheme() {
|
||||
return R.style.AppTheme_StatusBar_Dark;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_donation);
|
||||
new DonationActivity_ViewBinding(this);
|
||||
|
||||
setSupportActionBar(toolbar);
|
||||
toolbar.setNavigationOnClickListener(view -> finish());
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setTitle(R.string.donation);
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
paypal.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.PAYPAL_URL)));
|
||||
patreon.setOnClickListener(v -> Utils.openLink(this, Uri.parse(Const.Url.PATREON_URL)));
|
||||
}
|
||||
}
|
@@ -1,170 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.FlashZip;
|
||||
import com.topjohnwu.magisk.asyncs.InstallMagisk;
|
||||
import com.topjohnwu.magisk.components.BaseActivity;
|
||||
import com.topjohnwu.magisk.utils.Download;
|
||||
import com.topjohnwu.magisk.utils.RootUtils;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.CallbackList;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
|
||||
public class FlashActivity extends BaseActivity {
|
||||
|
||||
@BindView(R.id.toolbar) Toolbar toolbar;
|
||||
@BindView(R.id.txtLog) TextView flashLogs;
|
||||
@BindView(R.id.button_panel) public LinearLayout buttonPanel;
|
||||
@BindView(R.id.reboot) public Button reboot;
|
||||
@BindView(R.id.scrollView) ScrollView sv;
|
||||
|
||||
private List<String> logs;
|
||||
|
||||
@OnClick(R.id.reboot)
|
||||
void reboot() {
|
||||
Shell.su("/system/bin/reboot").submit();
|
||||
}
|
||||
|
||||
@OnClick(R.id.save_logs)
|
||||
void saveLogs() {
|
||||
runWithPermission(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, () -> {
|
||||
Calendar now = Calendar.getInstance();
|
||||
String filename = String.format(Locale.US,
|
||||
"magisk_install_log_%04d%02d%02d_%02d%02d%02d.log",
|
||||
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
|
||||
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
|
||||
now.get(Calendar.MINUTE), now.get(Calendar.SECOND));
|
||||
|
||||
File logFile = new File(Download.EXTERNAL_PATH, filename);
|
||||
try (FileWriter writer = new FileWriter(logFile)) {
|
||||
for (String s : logs) {
|
||||
writer.write(s);
|
||||
writer.write('\n');
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
Utils.toast(logFile.getPath(), Toast.LENGTH_LONG);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDarkTheme() {
|
||||
return R.style.AppTheme_StatusBar_Dark;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_flash);
|
||||
new FlashActivity_ViewBinding(this);
|
||||
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setTitle(R.string.flashing);
|
||||
}
|
||||
setFloating();
|
||||
setFinishOnTouchOutside(false);
|
||||
if (!Shell.rootAccess())
|
||||
reboot.setVisibility(View.GONE);
|
||||
|
||||
logs = new ArrayList<>();
|
||||
CallbackList<String> console = new CallbackList<String>(new ArrayList<>()) {
|
||||
|
||||
private void updateUI() {
|
||||
flashLogs.setText(TextUtils.join("\n", this));
|
||||
sv.postDelayed(() -> sv.fullScroll(ScrollView.FOCUS_DOWN), 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddElement(String s) {
|
||||
logs.add(s);
|
||||
updateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String set(int i, String s) {
|
||||
String ret = super.set(i, s);
|
||||
Data.mainHandler.post(this::updateUI);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// We must receive a Uri of the target zip
|
||||
Intent intent = getIntent();
|
||||
Uri uri = intent.getData();
|
||||
|
||||
switch (intent.getStringExtra(Const.Key.FLASH_ACTION)) {
|
||||
case Const.Value.FLASH_ZIP:
|
||||
new FlashZip(this, uri, console, logs).exec();
|
||||
break;
|
||||
case Const.Value.UNINSTALL:
|
||||
new UninstallMagisk(this, uri, console, logs).exec();
|
||||
break;
|
||||
case Const.Value.FLASH_MAGISK:
|
||||
new InstallMagisk(this, console, logs, InstallMagisk.DIRECT_MODE).exec();
|
||||
break;
|
||||
case Const.Value.FLASH_INACTIVE_SLOT:
|
||||
new InstallMagisk(this, console, logs, InstallMagisk.SECOND_SLOT_MODE).exec();
|
||||
break;
|
||||
case Const.Value.PATCH_BOOT:
|
||||
new InstallMagisk(this, console, logs,
|
||||
intent.getParcelableExtra(Const.Key.FLASH_SET_BOOT)).exec();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.close)
|
||||
@Override
|
||||
public void finish() {
|
||||
super.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// Prevent user accidentally press back button
|
||||
}
|
||||
|
||||
private static class UninstallMagisk extends FlashZip {
|
||||
|
||||
private UninstallMagisk(BaseActivity context, Uri uri, List<String> console, List<String> logs) {
|
||||
super(context, uri, console, logs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
if (result == 1) {
|
||||
Data.mainHandler.postDelayed(() ->
|
||||
RootUtils.uninstallPkg(getActivity().getPackageName()), 3000);
|
||||
} else {
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.database.MagiskDatabaseHelper;
|
||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
||||
import com.topjohnwu.magisk.utils.RootUtils;
|
||||
import com.topjohnwu.superuser.ContainerApp;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class MagiskManager extends ContainerApp {
|
||||
|
||||
// Info
|
||||
public boolean hasInit = false;
|
||||
|
||||
// Global resources
|
||||
public SharedPreferences prefs;
|
||||
public MagiskDatabaseHelper mDB;
|
||||
public RepoDatabaseHelper repoDB;
|
||||
|
||||
public MagiskManager() {
|
||||
Data.weakApp = new WeakReference<>(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER);
|
||||
Shell.Config.verboseLogging(BuildConfig.DEBUG);
|
||||
Shell.Config.setInitializer(RootUtils.class);
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
mDB = MagiskDatabaseHelper.getInstance();
|
||||
|
||||
String pkg = mDB.getStrings(Const.Key.SU_MANAGER, null);
|
||||
if (pkg != null && getPackageName().equals(Const.ORIG_PKG_NAME)) {
|
||||
mDB.setStrings(Const.Key.SU_MANAGER, null);
|
||||
Shell.su("pm uninstall " + pkg).exec();
|
||||
}
|
||||
if (TextUtils.equals(pkg, getPackageName())) {
|
||||
try {
|
||||
// We are the manager, remove com.topjohnwu.magisk as it could be malware
|
||||
getPackageManager().getApplicationInfo(Const.ORIG_PKG_NAME, 0);
|
||||
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);
|
||||
} catch (PackageManager.NameNotFoundException ignored) {}
|
||||
}
|
||||
|
||||
LocaleManager.setLocale(this);
|
||||
Data.loadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
LocaleManager.setLocale(this);
|
||||
}
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import com.topjohnwu.magisk.components.BaseActivity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class NoUIActivity extends BaseActivity {
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
finish();
|
||||
}
|
||||
}
|
@@ -1,67 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||
import com.topjohnwu.magisk.components.BaseActivity;
|
||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||
import com.topjohnwu.magisk.receivers.ShortcutReceiver;
|
||||
import com.topjohnwu.magisk.utils.Download;
|
||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
public class SplashActivity extends BaseActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Magisk working as expected
|
||||
if (Shell.rootAccess() && Data.magiskVersionCode > 0) {
|
||||
// Update check service
|
||||
Utils.setupUpdateCheck();
|
||||
// Load modules
|
||||
Utils.loadModules();
|
||||
}
|
||||
|
||||
mm.repoDB = new RepoDatabaseHelper(this);
|
||||
Data.importPrefs();
|
||||
|
||||
// Dynamic detect all locales
|
||||
LocaleManager.loadAvailableLocales();
|
||||
|
||||
// Create notification channel on Android O
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(Const.ID.NOTIFICATION_CHANNEL,
|
||||
getString(R.string.magisk_updates), NotificationManager.IMPORTANCE_DEFAULT);
|
||||
getSystemService(NotificationManager.class).createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
// Setup shortcuts
|
||||
sendBroadcast(new Intent(this, Data.classMap.get(ShortcutReceiver.class)));
|
||||
|
||||
if (Download.checkNetworkStatus(this)) {
|
||||
// Fire update check
|
||||
CheckUpdates.check();
|
||||
// Repo update check
|
||||
new UpdateRepos().exec();
|
||||
}
|
||||
|
||||
// Write back default values
|
||||
Data.writeConfig();
|
||||
|
||||
mm.hasInit = true;
|
||||
|
||||
Intent intent = new Intent(this, Data.classMap.get(MainActivity.class));
|
||||
intent.putExtra(Const.Key.OPEN_SECTION, getIntent().getStringExtra(Const.Key.OPEN_SECTION));
|
||||
intent.putExtra(BaseActivity.INTENT_PERM, getIntent().getStringExtra(BaseActivity.INTENT_PERM));
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
@@ -1,259 +0,0 @@
|
||||
package com.topjohnwu.magisk;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.net.LocalSocketAddress;
|
||||
import android.os.Bundle;
|
||||
import android.os.CountDownTimer;
|
||||
import android.os.FileObserver;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.components.BaseActivity;
|
||||
import com.topjohnwu.magisk.container.Policy;
|
||||
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
||||
import com.topjohnwu.magisk.utils.SuConnector;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import butterknife.BindView;
|
||||
|
||||
public class SuRequestActivity extends BaseActivity {
|
||||
@BindView(R.id.su_popup) LinearLayout suPopup;
|
||||
@BindView(R.id.timeout) Spinner timeout;
|
||||
@BindView(R.id.app_icon) ImageView appIcon;
|
||||
@BindView(R.id.app_name) TextView appNameView;
|
||||
@BindView(R.id.package_name) TextView packageNameView;
|
||||
@BindView(R.id.grant_btn) Button grant_btn;
|
||||
@BindView(R.id.deny_btn) Button deny_btn;
|
||||
@BindView(R.id.fingerprint) ImageView fingerprintImg;
|
||||
@BindView(R.id.warning) TextView warning;
|
||||
|
||||
private SuConnector connector;
|
||||
private Policy policy;
|
||||
private CountDownTimer timer;
|
||||
private FingerprintHelper fingerprintHelper;
|
||||
|
||||
class SuConnectorV1 extends SuConnector {
|
||||
|
||||
SuConnectorV1(String name) throws IOException {
|
||||
socket.connect(new LocalSocketAddress(name, LocalSocketAddress.Namespace.FILESYSTEM));
|
||||
new FileObserver(name) {
|
||||
@Override
|
||||
public void onEvent(int fileEvent, String path) {
|
||||
if (fileEvent == FileObserver.DELETE_SELF) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}.startWatching();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void response() {
|
||||
try (OutputStream out = getOutputStream()) {
|
||||
out.write((policy.policy == Policy.ALLOW ? "socket:ALLOW" : "socket:DENY").getBytes());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SuConnectorV2 extends SuConnector {
|
||||
|
||||
SuConnectorV2(String name) throws IOException {
|
||||
socket.connect(new LocalSocketAddress(name, LocalSocketAddress.Namespace.ABSTRACT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void response() {
|
||||
try (DataOutputStream out = getOutputStream()) {
|
||||
out.writeInt(policy.policy);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDarkTheme() {
|
||||
return R.style.SuRequest_Dark;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (timer != null)
|
||||
timer.cancel();
|
||||
if (fingerprintHelper != null)
|
||||
fingerprintHelper.cancel();
|
||||
super.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (policy != null) {
|
||||
handleAction(Policy.DENY);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
PackageManager pm = getPackageManager();
|
||||
mm.mDB.clearOutdated();
|
||||
|
||||
// Get policy
|
||||
Intent intent = getIntent();
|
||||
try {
|
||||
connector = intent.getIntExtra("version", 1) == 1 ?
|
||||
new SuConnectorV1(intent.getStringExtra("socket")) :
|
||||
new SuConnectorV2(intent.getStringExtra("socket"));
|
||||
Bundle bundle = connector.readSocketInput();
|
||||
int uid = Integer.parseInt(bundle.getString("uid"));
|
||||
policy = mm.mDB.getPolicy(uid);
|
||||
if (policy == null) {
|
||||
policy = new Policy(uid, pm);
|
||||
}
|
||||
} catch (IOException | PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Never allow com.topjohnwu.magisk (could be malware)
|
||||
if (TextUtils.equals(policy.packageName, Const.ORIG_PKG_NAME)) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Data.suResponseType) {
|
||||
case Const.Value.SU_AUTO_DENY:
|
||||
handleAction(Policy.DENY, 0);
|
||||
return;
|
||||
case Const.Value.SU_AUTO_ALLOW:
|
||||
handleAction(Policy.ALLOW, 0);
|
||||
return;
|
||||
case Const.Value.SU_PROMPT:
|
||||
default:
|
||||
}
|
||||
|
||||
// If not interactive, response directly
|
||||
if (policy.policy != Policy.INTERACTIVE) {
|
||||
handleAction();
|
||||
return;
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_request);
|
||||
new SuRequestActivity_ViewBinding(this);
|
||||
|
||||
appIcon.setImageDrawable(policy.info.loadIcon(pm));
|
||||
appNameView.setText(policy.appName);
|
||||
packageNameView.setText(policy.packageName);
|
||||
|
||||
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
|
||||
R.array.allow_timeout, android.R.layout.simple_spinner_item);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
timeout.setAdapter(adapter);
|
||||
|
||||
timer = new CountDownTimer(Data.suRequestTimeout * 1000, 1000) {
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
deny_btn.setText(getString(R.string.deny_with_str, "(" + millisUntilFinished / 1000 + ")"));
|
||||
}
|
||||
@Override
|
||||
public void onFinish() {
|
||||
deny_btn.setText(getString(R.string.deny_with_str, "(0)"));
|
||||
handleAction(Policy.DENY);
|
||||
}
|
||||
};
|
||||
|
||||
boolean useFingerprint = Data.suFingerprint && FingerprintHelper.canUseFingerprint();
|
||||
|
||||
if (useFingerprint) {
|
||||
try {
|
||||
fingerprintHelper = new FingerprintHelper() {
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, CharSequence errString) {
|
||||
warning.setText(errString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
|
||||
warning.setText(helpString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
|
||||
handleAction(Policy.ALLOW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
warning.setText(R.string.auth_fail);
|
||||
}
|
||||
};
|
||||
fingerprintHelper.authenticate();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
useFingerprint = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!useFingerprint) {
|
||||
grant_btn.setOnClickListener(v -> {
|
||||
handleAction(Policy.ALLOW);
|
||||
timer.cancel();
|
||||
});
|
||||
grant_btn.requestFocus();
|
||||
}
|
||||
|
||||
grant_btn.setVisibility(useFingerprint ? View.GONE : View.VISIBLE);
|
||||
fingerprintImg.setVisibility(useFingerprint ? View.VISIBLE : View.GONE);
|
||||
|
||||
deny_btn.setOnClickListener(v -> {
|
||||
handleAction(Policy.DENY);
|
||||
timer.cancel();
|
||||
});
|
||||
suPopup.setOnClickListener(v -> cancelTimeout());
|
||||
timeout.setOnTouchListener((v, event) -> cancelTimeout());
|
||||
timer.start();
|
||||
}
|
||||
|
||||
private boolean cancelTimeout() {
|
||||
timer.cancel();
|
||||
deny_btn.setText(getString(R.string.deny));
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleAction() {
|
||||
connector.response();
|
||||
finish();
|
||||
}
|
||||
|
||||
private void handleAction(int action) {
|
||||
handleAction(action, Const.Value.timeoutList[timeout.getSelectedItemPosition()]);
|
||||
}
|
||||
|
||||
private void handleAction(int action, int time) {
|
||||
policy.policy = action;
|
||||
if (time >= 0) {
|
||||
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
|
||||
mm.mDB.addPolicy(policy);
|
||||
}
|
||||
handleAction();
|
||||
}
|
||||
}
|
@@ -1,152 +0,0 @@
|
||||
package com.topjohnwu.magisk.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.Filter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
|
||||
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.ViewHolder> {
|
||||
|
||||
private List<ApplicationInfo> fullList, showList;
|
||||
private List<String> hideList;
|
||||
private PackageManager pm;
|
||||
private ApplicationFilter filter;
|
||||
|
||||
public ApplicationAdapter(Context context) {
|
||||
fullList = showList = Collections.emptyList();
|
||||
hideList = Collections.emptyList();
|
||||
filter = new ApplicationFilter();
|
||||
pm = context.getPackageManager();
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(this::loadApps);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_app, parent, false);
|
||||
return new ViewHolder(v);
|
||||
}
|
||||
|
||||
private void loadApps() {
|
||||
fullList = pm.getInstalledApplications(0);
|
||||
hideList = Shell.su("magiskhide --ls").exec().getOut();
|
||||
for (Iterator<ApplicationInfo> i = fullList.iterator(); i.hasNext(); ) {
|
||||
ApplicationInfo info = i.next();
|
||||
if (Const.HIDE_BLACKLIST.contains(info.packageName) || !info.enabled || info.uid == 1000) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
Collections.sort(fullList, (a, b) -> {
|
||||
boolean ah = hideList.contains(a.packageName);
|
||||
boolean bh = hideList.contains(b.packageName);
|
||||
if (ah == bh) {
|
||||
return Utils.getAppLabel(a, pm).toLowerCase()
|
||||
.compareTo(Utils.getAppLabel(b, pm).toLowerCase());
|
||||
} else if (ah) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
Topic.publish(false, Topic.MAGISK_HIDE_DONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
ApplicationInfo info = showList.get(position);
|
||||
|
||||
holder.appIcon.setImageDrawable(info.loadIcon(pm));
|
||||
holder.appName.setText(Utils.getAppLabel(info, pm));
|
||||
holder.appPackage.setText(info.packageName);
|
||||
|
||||
holder.checkBox.setOnCheckedChangeListener(null);
|
||||
holder.checkBox.setChecked(hideList.contains(info.packageName));
|
||||
holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> {
|
||||
if (isChecked) {
|
||||
Shell.su("magiskhide --add " + info.packageName).submit();
|
||||
hideList.add(info.packageName);
|
||||
} else {
|
||||
Shell.su("magiskhide --rm " + info.packageName).submit();
|
||||
hideList.remove(info.packageName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return showList.size();
|
||||
}
|
||||
|
||||
public void filter(String constraint) {
|
||||
filter.filter(constraint);
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(this::loadApps);
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
@BindView(R.id.app_icon) ImageView appIcon;
|
||||
@BindView(R.id.app_name) TextView appName;
|
||||
@BindView(R.id.package_name) TextView appPackage;
|
||||
@BindView(R.id.checkbox) CheckBox checkBox;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
new ApplicationAdapter$ViewHolder_ViewBinding(this, itemView);
|
||||
}
|
||||
}
|
||||
|
||||
class ApplicationFilter extends Filter {
|
||||
|
||||
private boolean lowercaseContains(String s, CharSequence filter) {
|
||||
return !TextUtils.isEmpty(s) && s.toLowerCase().contains(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FilterResults performFiltering(CharSequence constraint) {
|
||||
if (constraint == null || constraint.length() == 0) {
|
||||
showList = fullList;
|
||||
} else {
|
||||
showList = new ArrayList<>();
|
||||
String filter = constraint.toString().toLowerCase();
|
||||
for (ApplicationInfo info : fullList) {
|
||||
if (lowercaseContains(Utils.getAppLabel(info, pm), filter)
|
||||
|| lowercaseContains(info.packageName, filter)) {
|
||||
showList.add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void publishResults(CharSequence constraint, FilterResults results) {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,77 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
import dalvik.system.DexClassLoader;
|
||||
|
||||
public class CheckSafetyNet extends ParallelTask<Void, Void, Void> {
|
||||
|
||||
public static final File dexPath =
|
||||
new File(Data.MM().getFilesDir().getParent() + "/snet", "snet.apk");
|
||||
private ISafetyNetHelper helper;
|
||||
|
||||
public CheckSafetyNet(Activity activity) {
|
||||
super(activity);
|
||||
}
|
||||
|
||||
private void dlSnet() throws Exception {
|
||||
Shell.sh("rm -rf " + dexPath.getParent()).exec();
|
||||
dexPath.getParentFile().mkdir();
|
||||
HttpURLConnection conn = WebService.mustRequest(Data.snetLink, null);
|
||||
try (
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath));
|
||||
InputStream in = new BufferedInputStream(conn.getInputStream())) {
|
||||
ShellUtils.pump(in, out);
|
||||
} finally {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private void dyload() throws Exception {
|
||||
DexClassLoader loader = new DexClassLoader(dexPath.getPath(), dexPath.getParent(),
|
||||
null, ISafetyNetHelper.class.getClassLoader());
|
||||
Class<?> clazz = loader.loadClass("com.topjohnwu.snet.Snet");
|
||||
helper = (ISafetyNetHelper) clazz.getMethod("newHelper",
|
||||
Class.class, String.class, Activity.class, Object.class)
|
||||
.invoke(null, ISafetyNetHelper.class, dexPath.getPath(), getActivity(),
|
||||
(ISafetyNetHelper.Callback) code ->
|
||||
Topic.publish(false, Topic.SNET_CHECK_DONE, code));
|
||||
if (helper.getVersion() < Data.snetVersionCode) {
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
try {
|
||||
try {
|
||||
dyload();
|
||||
} catch (Exception e) {
|
||||
// If dynamic load failed, try re-downloading and reload
|
||||
dlSnet();
|
||||
dyload();
|
||||
}
|
||||
// Run attestation
|
||||
helper.attest();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Topic.publish(false, Topic.SNET_CHECK_DONE, -1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,105 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.topjohnwu.magisk.BuildConfig;
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.utils.NotificationMgr;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class CheckUpdates {
|
||||
|
||||
private static int getInt(JSONObject json, String name, int defValue) {
|
||||
if (json == null)
|
||||
return defValue;
|
||||
try {
|
||||
return json.getInt(name);
|
||||
} catch (JSONException e) {
|
||||
return defValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getString(JSONObject json, String name, String defValue) {
|
||||
if (json == null)
|
||||
return defValue;
|
||||
try {
|
||||
return json.getString(name);
|
||||
} catch (JSONException e) {
|
||||
return defValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static JSONObject getJson(JSONObject json, String name) {
|
||||
try {
|
||||
return json.getJSONObject(name);
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void fetchUpdates() {
|
||||
String jsonStr = "";
|
||||
switch (Data.updateChannel) {
|
||||
case Const.Value.STABLE_CHANNEL:
|
||||
jsonStr = WebService.getString(Const.Url.STABLE_URL);
|
||||
break;
|
||||
case Const.Value.BETA_CHANNEL:
|
||||
jsonStr = WebService.getString(Const.Url.BETA_URL);
|
||||
break;
|
||||
case Const.Value.CUSTOM_CHANNEL:
|
||||
jsonStr = WebService.getString(Data.MM().prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
||||
break;
|
||||
}
|
||||
|
||||
JSONObject json;
|
||||
try {
|
||||
json = new JSONObject(jsonStr);
|
||||
} catch (JSONException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSONObject magisk = getJson(json, "magisk");
|
||||
Data.remoteMagiskVersionString = getString(magisk, "version", null);
|
||||
Data.remoteMagiskVersionCode = getInt(magisk, "versionCode", -1);
|
||||
Data.magiskLink = getString(magisk, "link", null);
|
||||
Data.magiskNoteLink = getString(magisk, "note", null);
|
||||
Data.magiskMD5 = getString(magisk, "md5", null);
|
||||
|
||||
JSONObject manager = getJson(json, "app");
|
||||
Data.remoteManagerVersionString = getString(manager, "version", null);
|
||||
Data.remoteManagerVersionCode = getInt(manager, "versionCode", -1);
|
||||
Data.managerLink = getString(manager, "link", null);
|
||||
Data.managerNoteLink = getString(manager, "note", null);
|
||||
|
||||
JSONObject uninstaller = getJson(json, "uninstaller");
|
||||
Data.uninstallerLink = getString(uninstaller, "link", null);
|
||||
|
||||
JSONObject snet = getJson(json, "snet");
|
||||
Data.snetVersionCode = getInt(snet, "versionCode", -1);
|
||||
Data.snetLink = getString(snet, "link", null);
|
||||
}
|
||||
|
||||
public static void check(Runnable cb) {
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
fetchUpdates();
|
||||
if (cb != null) {
|
||||
if (BuildConfig.VERSION_CODE < Data.remoteManagerVersionCode) {
|
||||
NotificationMgr.managerUpdate();
|
||||
} else if (Data.magiskVersionCode < Data.remoteMagiskVersionCode) {
|
||||
NotificationMgr.magiskUpdate();
|
||||
}
|
||||
cb.run();
|
||||
}
|
||||
Topic.publish(Topic.UPDATE_CHECK_DONE);
|
||||
});
|
||||
}
|
||||
|
||||
public static void check() {
|
||||
check(null);
|
||||
}
|
||||
}
|
@@ -1,104 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.FlashActivity;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class FlashZip extends ParallelTask<Void, Void, Integer> {
|
||||
|
||||
private Uri mUri;
|
||||
private File mCachedFile;
|
||||
private List<String> console, logs;
|
||||
|
||||
public FlashZip(Activity context, Uri uri, List<String> console, List<String> logs) {
|
||||
super(context);
|
||||
mUri = uri;
|
||||
this.console = console;
|
||||
this.logs = logs;
|
||||
mCachedFile = new File(context.getCacheDir(), "install.zip");
|
||||
}
|
||||
|
||||
private boolean unzipAndCheck() throws Exception {
|
||||
ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", true);
|
||||
return ShellUtils.fastCmdResult("grep -q '#MAGISK' " + new File(mCachedFile.getParentFile(), "updater-script"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... voids) {
|
||||
MagiskManager mm = Data.MM();
|
||||
try {
|
||||
console.add("- Copying zip to temp directory");
|
||||
|
||||
mCachedFile.delete();
|
||||
try (
|
||||
InputStream in = mm.getContentResolver().openInputStream(mUri);
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(mCachedFile))
|
||||
) {
|
||||
if (in == null) throw new FileNotFoundException();
|
||||
InputStream buf= new BufferedInputStream(in);
|
||||
ShellUtils.pump(buf, out);
|
||||
} catch (FileNotFoundException e) {
|
||||
console.add("! Invalid Uri");
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
console.add("! Cannot copy to cache");
|
||||
throw e;
|
||||
}
|
||||
if (!unzipAndCheck()) return 0;
|
||||
console.add("- Installing " + Utils.getNameFromUri(mm, mUri));
|
||||
if (!Shell.su("cd " + mCachedFile.getParent(),
|
||||
"BOOTMODE=true sh update-binary dummy 1 " + mCachedFile)
|
||||
.to(console, logs)
|
||||
.exec().isSuccess())
|
||||
return -1;
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
console.add("- All done!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// -1 = error, manual install; 0 = invalid zip; 1 = success
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
FlashActivity activity = (FlashActivity) getActivity();
|
||||
Shell.su("rm -rf " + mCachedFile.getParent(), "rm -rf " + Const.TMP_FOLDER_PATH).submit();
|
||||
switch (result) {
|
||||
case -1:
|
||||
console.add("! Installation failed");
|
||||
SnackbarMaker.showUri(getActivity(), mUri);
|
||||
break;
|
||||
case 0:
|
||||
console.add("! This zip is not a Magisk Module!");
|
||||
break;
|
||||
case 1:
|
||||
// Reload modules
|
||||
Utils.loadModules();
|
||||
break;
|
||||
}
|
||||
activity.reboot.setVisibility(result > 0 ? View.VISIBLE : View.GONE);
|
||||
activity.buttonPanel.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
@@ -1,398 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.FlashActivity;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.container.TarEntry;
|
||||
import com.topjohnwu.magisk.utils.Download;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
import com.topjohnwu.superuser.internal.NOPList;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
import com.topjohnwu.superuser.io.SuFileInputStream;
|
||||
import com.topjohnwu.superuser.io.SuFileOutputStream;
|
||||
import com.topjohnwu.utils.SignBoot;
|
||||
|
||||
import org.kamranzafar.jtar.TarInputStream;
|
||||
import org.kamranzafar.jtar.TarOutputStream;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class InstallMagisk extends ParallelTask<Void, Void, Boolean> {
|
||||
|
||||
private static final int PATCH_MODE = 0;
|
||||
public static final int DIRECT_MODE = 1;
|
||||
private static final int FIX_ENV_MODE = 2;
|
||||
public static final int SECOND_SLOT_MODE = 3;
|
||||
|
||||
private Uri bootUri;
|
||||
private List<String> console, logs;
|
||||
private String mBoot;
|
||||
private int mode;
|
||||
private File installDir;
|
||||
private ProgressDialog dialog;
|
||||
private MagiskManager mm;
|
||||
|
||||
public InstallMagisk(Activity context) {
|
||||
super(context);
|
||||
mm = Data.MM();
|
||||
mode = FIX_ENV_MODE;
|
||||
}
|
||||
|
||||
public InstallMagisk(Activity context, List<String> console, List<String> logs, int mode) {
|
||||
this(context);
|
||||
this.console = console;
|
||||
this.logs = logs;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public InstallMagisk(FlashActivity context, List<String> console, List<String> logs, Uri boot) {
|
||||
this(context, console, logs, PATCH_MODE);
|
||||
bootUri = boot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
if (mode == FIX_ENV_MODE) {
|
||||
Activity a = getActivity();
|
||||
dialog = ProgressDialog.show(a, a.getString(R.string.setup_title), a.getString(R.string.setup_msg));
|
||||
console = NOPList.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
private class ProgressStream extends FilterInputStream {
|
||||
|
||||
private int prev = -1;
|
||||
private int progress = 0;
|
||||
private int total;
|
||||
|
||||
private ProgressStream(HttpURLConnection conn) throws IOException {
|
||||
super(conn.getInputStream());
|
||||
total = conn.getContentLength();
|
||||
console.add("... 0%");
|
||||
}
|
||||
|
||||
private void update(int step) {
|
||||
progress += step;
|
||||
int curr = (int) (100 * (double) progress / total);
|
||||
if (prev != curr) {
|
||||
prev = curr;
|
||||
console.set(console.size() - 1, "... " + prev + "%");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
int b = super.read();
|
||||
if (b > 0)
|
||||
update(1);
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] b, int off, int len) throws IOException {
|
||||
int step = super.read(b, off, len);
|
||||
if (step > 0)
|
||||
update(step);
|
||||
return step;
|
||||
}
|
||||
}
|
||||
|
||||
private void extractFiles(String arch) throws IOException {
|
||||
File zip = new File(mm.getFilesDir(), "magisk.zip");
|
||||
BufferedInputStream buf;
|
||||
|
||||
if (!ShellUtils.checkSum("MD5", zip, Data.magiskMD5)) {
|
||||
console.add("- Downloading zip");
|
||||
HttpURLConnection conn = WebService.mustRequest(Data.magiskLink, null);
|
||||
buf = new BufferedInputStream(new ProgressStream(conn), conn.getContentLength());
|
||||
buf.mark(conn.getContentLength() + 1);
|
||||
try (OutputStream out = new FileOutputStream(zip)) {
|
||||
ShellUtils.pump(buf, out);
|
||||
}
|
||||
buf.reset();
|
||||
conn.disconnect();
|
||||
} else {
|
||||
console.add("- Existing zip found");
|
||||
buf = new BufferedInputStream(new FileInputStream(zip), (int) zip.length());
|
||||
buf.mark((int) zip.length() + 1);
|
||||
}
|
||||
|
||||
console.add("- Extracting files");
|
||||
try (InputStream in = buf) {
|
||||
ZipUtils.unzip(in, installDir, arch + "/", true);
|
||||
in.reset();
|
||||
ZipUtils.unzip(in, installDir, "common/", true);
|
||||
in.reset();
|
||||
ZipUtils.unzip(in, installDir, "chromeos/", false);
|
||||
in.reset();
|
||||
ZipUtils.unzip(in, installDir, "META-INF/com/google/android/update-binary", true);
|
||||
} catch (IOException e) {
|
||||
console.add("! Cannot unzip zip");
|
||||
throw e;
|
||||
}
|
||||
Shell.sh(Utils.fmt("chmod -R 755 %s/*; %s/magiskinit -x magisk %s/magisk",
|
||||
installDir, installDir, installDir)).exec();
|
||||
}
|
||||
|
||||
private boolean dumpBoot() {
|
||||
console.add("- Copying image to cache");
|
||||
// Copy boot image to local
|
||||
try (InputStream in = mm.getContentResolver().openInputStream(bootUri);
|
||||
OutputStream out = new FileOutputStream(mBoot)
|
||||
) {
|
||||
if (in == null)
|
||||
throw new FileNotFoundException();
|
||||
|
||||
InputStream src;
|
||||
if (Utils.getNameFromUri(mm, bootUri).endsWith(".tar")) {
|
||||
// Extract boot.img from tar
|
||||
TarInputStream tar = new TarInputStream(new BufferedInputStream(in));
|
||||
org.kamranzafar.jtar.TarEntry entry;
|
||||
while ((entry = tar.getNextEntry()) != null) {
|
||||
if (entry.getName().equals("boot.img"))
|
||||
break;
|
||||
}
|
||||
src = tar;
|
||||
} else {
|
||||
// Direct copy raw image
|
||||
src = new BufferedInputStream(in);
|
||||
}
|
||||
ShellUtils.pump(src, out);
|
||||
} catch (FileNotFoundException e) {
|
||||
console.add("! Invalid Uri");
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
console.add("! Copy failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private File patchBoot() throws IOException {
|
||||
boolean isSigned;
|
||||
try (InputStream in = new SuFileInputStream(mBoot)) {
|
||||
isSigned = SignBoot.verifySignature(in, null);
|
||||
if (isSigned) {
|
||||
console.add("- Boot image is signed with AVB 1.0");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
console.add("! Unable to check signature");
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Patch boot image
|
||||
if (!Shell.sh("cd " + installDir, Utils.fmt(
|
||||
"KEEPFORCEENCRYPT=%b KEEPVERITY=%b sh update-binary indep boot_patch.sh %s",
|
||||
Data.keepEnc, Data.keepVerity, mBoot))
|
||||
.to(console, logs).exec().isSuccess())
|
||||
return null;
|
||||
|
||||
Shell.Job job = Shell.sh("mv bin/busybox busybox",
|
||||
"rm -rf magisk.apk bin boot.img update-binary",
|
||||
"cd /");
|
||||
|
||||
File patched = new File(installDir, "new-boot.img");
|
||||
if (isSigned) {
|
||||
console.add("- Signing boot image with test keys");
|
||||
File signed = new File(installDir, "signed.img");
|
||||
try (InputStream in = new SuFileInputStream(patched);
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(signed))
|
||||
) {
|
||||
SignBoot.doSignature("/boot", in, out, null, null);
|
||||
}
|
||||
job.add("mv -f " + signed + " " + patched);
|
||||
}
|
||||
job.exec();
|
||||
return patched;
|
||||
}
|
||||
|
||||
private boolean outputBoot(File patched) throws IOException {
|
||||
switch (mode) {
|
||||
case PATCH_MODE:
|
||||
String fmt = mm.prefs.getString(Const.Key.BOOT_FORMAT, ".img");
|
||||
File dest = new File(Download.EXTERNAL_PATH, "patched_boot" + fmt);
|
||||
dest.getParentFile().mkdirs();
|
||||
OutputStream out;
|
||||
switch (fmt) {
|
||||
case ".img.tar":
|
||||
out = new TarOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
|
||||
((TarOutputStream) out).putNextEntry(new TarEntry(patched, "boot.img"));
|
||||
break;
|
||||
default:
|
||||
case ".img":
|
||||
out = new BufferedOutputStream(new FileOutputStream(dest));
|
||||
break;
|
||||
}
|
||||
try (InputStream in = new SuFileInputStream(patched)) {
|
||||
ShellUtils.pump(in, out);
|
||||
out.close();
|
||||
}
|
||||
Shell.sh("rm -f " + patched).exec();
|
||||
console.add("");
|
||||
console.add("****************************");
|
||||
console.add(" Patched image is placed in ");
|
||||
console.add(" " + dest + " ");
|
||||
console.add("****************************");
|
||||
break;
|
||||
case SECOND_SLOT_MODE:
|
||||
case DIRECT_MODE:
|
||||
if (!Shell.su(Utils.fmt("direct_install %s %s", installDir, mBoot))
|
||||
.to(console, logs).exec().isSuccess())
|
||||
return false;
|
||||
if (!Data.keepVerity)
|
||||
Shell.su("find_dtbo_image", "patch_dtbo_image").to(console, logs).exec();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void postOTA() {
|
||||
SuFile bootctl = new SuFile(Const.MAGISK_PATH + "/.core/bootctl");
|
||||
try (InputStream in = mm.getResources().openRawResource(R.raw.bootctl);
|
||||
OutputStream out = new SuFileOutputStream(bootctl)) {
|
||||
ShellUtils.pump(in, out);
|
||||
Shell.su("post_ota " + bootctl.getParent()).exec();
|
||||
console.add("***************************************");
|
||||
console.add(" Next reboot will boot to second slot!");
|
||||
console.add("***************************************");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
if (mode == FIX_ENV_MODE) {
|
||||
installDir = new File("/data/adb/magisk");
|
||||
Shell.su("rm -rf /data/adb/magisk/*").exec();
|
||||
} else {
|
||||
installDir = new File(
|
||||
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?
|
||||
mm.createDeviceProtectedStorageContext() : mm)
|
||||
.getFilesDir().getParent()
|
||||
, "install");
|
||||
Shell.sh("rm -rf " + installDir).exec();
|
||||
installDir.mkdirs();
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case PATCH_MODE:
|
||||
mBoot = new File(installDir, "boot.img").getAbsolutePath();
|
||||
if (!dumpBoot())
|
||||
return false;
|
||||
break;
|
||||
case DIRECT_MODE:
|
||||
console.add("- Detecting target image");
|
||||
mBoot = ShellUtils.fastCmd("find_boot_image", "echo \"$BOOTIMAGE\"");
|
||||
break;
|
||||
case SECOND_SLOT_MODE:
|
||||
String slot = ShellUtils.fastCmd("echo $SLOT");
|
||||
String target = (TextUtils.equals(slot, "_a") ? "_b" : "_a");
|
||||
console.add("- Target slot: " + target);
|
||||
console.add("- Detecting target image");
|
||||
mBoot = ShellUtils.fastCmd(
|
||||
"SLOT=" + target,
|
||||
"find_boot_image",
|
||||
"SLOT=" + slot,
|
||||
"echo \"$BOOTIMAGE\""
|
||||
);
|
||||
break;
|
||||
case FIX_ENV_MODE:
|
||||
mBoot = "";
|
||||
break;
|
||||
}
|
||||
if (mBoot == null) {
|
||||
console.add("! Unable to detect target image");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode == DIRECT_MODE || mode == SECOND_SLOT_MODE)
|
||||
console.add("- Target image: " + mBoot);
|
||||
|
||||
List<String> abis = Arrays.asList(Build.SUPPORTED_ABIS);
|
||||
String arch;
|
||||
|
||||
if (Data.remoteMagiskVersionCode >= Const.MAGISK_VER.SEPOL_REFACTOR) {
|
||||
// 32-bit only
|
||||
if (abis.contains("x86")) arch = "x86";
|
||||
else arch = "arm";
|
||||
} else {
|
||||
if (abis.contains("x86_64")) arch = "x64";
|
||||
else if (abis.contains("arm64-v8a")) arch = "arm64";
|
||||
else if (abis.contains("x86")) arch = "x86";
|
||||
else arch = "arm";
|
||||
}
|
||||
|
||||
console.add("- Device platform: " + Build.SUPPORTED_ABIS[0]);
|
||||
|
||||
try {
|
||||
extractFiles(arch);
|
||||
if (mode == FIX_ENV_MODE) {
|
||||
Shell.su("fix_env").exec();
|
||||
} else {
|
||||
File patched = patchBoot();
|
||||
if (patched == null)
|
||||
return false;
|
||||
if (!outputBoot(patched))
|
||||
return false;
|
||||
if (mode == SECOND_SLOT_MODE)
|
||||
postOTA();
|
||||
console.add("- All done!");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
if (mode == FIX_ENV_MODE) {
|
||||
dialog.dismiss();
|
||||
Utils.toast(result ? R.string.setup_done : R.string.setup_fail, Toast.LENGTH_LONG);
|
||||
} else {
|
||||
// Running in FlashActivity
|
||||
FlashActivity activity = (FlashActivity) getActivity();
|
||||
if (!result) {
|
||||
Shell.sh("rm -rf " + installDir).submit();
|
||||
console.add("! Installation failed");
|
||||
activity.reboot.setVisibility(View.GONE);
|
||||
}
|
||||
activity.buttonPanel.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,88 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.parser.Parser;
|
||||
import org.commonmark.renderer.html.HtmlRenderer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
public class MarkDownWindow extends ParallelTask<Void, Void, String> {
|
||||
|
||||
private String mTitle;
|
||||
private String mUrl;
|
||||
private InputStream is;
|
||||
|
||||
|
||||
public MarkDownWindow(Activity context, String title, String url) {
|
||||
super(context);
|
||||
mTitle = title;
|
||||
mUrl = url;
|
||||
}
|
||||
|
||||
public MarkDownWindow(Activity context, String title, InputStream in) {
|
||||
super(context);
|
||||
mTitle = title;
|
||||
is = in;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... voids) {
|
||||
MagiskManager mm = Data.MM();
|
||||
String md;
|
||||
if (mUrl != null) {
|
||||
md = WebService.getString(mUrl);
|
||||
} else {
|
||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
ShellUtils.pump(is, out);
|
||||
md = out.toString();
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
String css;
|
||||
try (
|
||||
InputStream in = mm.getResources().openRawResource(
|
||||
Data.isDarkTheme ? R.raw.dark : R.raw.light);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream()
|
||||
) {
|
||||
ShellUtils.pump(in, out);
|
||||
css = out.toString();
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
Parser parser = Parser.builder().build();
|
||||
HtmlRenderer renderer = HtmlRenderer.builder().build();
|
||||
Node doc = parser.parse(md);
|
||||
return String.format("<style>%s</style>%s", css, renderer.render(doc));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String html) {
|
||||
AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
|
||||
alert.setTitle(mTitle);
|
||||
|
||||
WebView wv = new WebView(getActivity());
|
||||
wv.loadDataWithBaseURL("fake://", html, "text/html", "UTF-8", null);
|
||||
|
||||
alert.setView(wv);
|
||||
alert.setNegativeButton(R.string.close, (dialog, id) -> dialog.dismiss());
|
||||
alert.show();
|
||||
}
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public abstract class ParallelTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
|
||||
|
||||
private WeakReference<Activity> weakActivity;
|
||||
|
||||
public ParallelTask() {}
|
||||
|
||||
public ParallelTask(Activity context) {
|
||||
weakActivity = new WeakReference<>(context);
|
||||
}
|
||||
|
||||
protected Activity getActivity() {
|
||||
return weakActivity.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void exec(Params... params) {
|
||||
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
|
||||
}
|
||||
}
|
@@ -1,154 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.os.AsyncTask;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.RootUtils;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
import com.topjohnwu.superuser.io.SuFileOutputStream;
|
||||
import com.topjohnwu.utils.JarMap;
|
||||
import com.topjohnwu.utils.SignAPK;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.jar.JarEntry;
|
||||
|
||||
public class PatchAPK {
|
||||
|
||||
private static String genPackageName(String prefix, int length) {
|
||||
StringBuilder builder = new StringBuilder(length);
|
||||
builder.append(prefix);
|
||||
length -= prefix.length();
|
||||
SecureRandom random = new SecureRandom();
|
||||
String base = "abcdefghijklmnopqrstuvwxyz";
|
||||
String alpha = base + base.toUpperCase();
|
||||
String full = alpha + "0123456789..........";
|
||||
char next, prev = '\0';
|
||||
for (int i = 0; i < length; ++i) {
|
||||
if (prev == '.' || i == length - 1 || i == 0) {
|
||||
next = alpha.charAt(random.nextInt(alpha.length()));
|
||||
} else {
|
||||
next = full.charAt(random.nextInt(full.length()));
|
||||
}
|
||||
builder.append(next);
|
||||
prev = next;
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static int findOffset(byte buf[], byte pattern[]) {
|
||||
int offset = -1;
|
||||
for (int i = 0; i < buf.length - pattern.length; ++i) {
|
||||
boolean match = true;
|
||||
for (int j = 0; j < pattern.length; ++j) {
|
||||
if (buf[i + j] != pattern[j]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
offset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* It seems that AAPT sometimes generate another type of string format */
|
||||
private static boolean fallbackPatch(byte xml[], String from, String to) {
|
||||
|
||||
byte[] target = new byte[from.length() * 2 + 2];
|
||||
for (int i = 0; i < from.length(); ++i) {
|
||||
target[i * 2] = (byte) from.charAt(i);
|
||||
}
|
||||
int offset = findOffset(xml, target);
|
||||
if (offset < 0)
|
||||
return false;
|
||||
byte[] dest = new byte[target.length - 2];
|
||||
for (int i = 0; i < to.length(); ++i) {
|
||||
dest[i * 2] = (byte) to.charAt(i);
|
||||
}
|
||||
System.arraycopy(dest, 0, xml, offset, dest.length);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean findAndPatch(byte xml[], String from, String to) {
|
||||
byte target[] = (from + '\0').getBytes();
|
||||
int offset = findOffset(xml, target);
|
||||
if (offset < 0)
|
||||
return fallbackPatch(xml, from, to);
|
||||
System.arraycopy(to.getBytes(), 0, xml, offset, to.length());
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean patchAndHide() {
|
||||
MagiskManager mm = Data.MM();
|
||||
|
||||
// Generate a new app with random package name
|
||||
SuFile repack = new SuFile("/data/local/tmp/repack.apk");
|
||||
String pkg = genPackageName("com.", Const.ORIG_PKG_NAME.length());
|
||||
|
||||
try {
|
||||
JarMap apk = new JarMap(mm.getPackageCodePath());
|
||||
if (!patchPackageID(apk, Const.ORIG_PKG_NAME, pkg))
|
||||
return false;
|
||||
SignAPK.sign(apk, new SuFileOutputStream(repack));
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Install the application
|
||||
if (!ShellUtils.fastCmdResult("pm install " + repack))
|
||||
return false;
|
||||
|
||||
repack.delete();
|
||||
|
||||
mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
|
||||
mm.mDB.flush();
|
||||
Data.exportPrefs();
|
||||
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean patchPackageID(JarMap apk, String from, String to) {
|
||||
try {
|
||||
JarEntry je = apk.getJarEntry(Const.ANDROID_MANIFEST);
|
||||
byte xml[] = apk.getRawData(je);
|
||||
|
||||
if (!findAndPatch(xml, from, to))
|
||||
return false;
|
||||
if (!findAndPatch(xml, from + ".provider", to + ".provider"))
|
||||
return false;
|
||||
|
||||
// Write in changes
|
||||
apk.getOutputStream(je).write(xml);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void hideManager(Activity activity) {
|
||||
ProgressDialog dialog = ProgressDialog.show(activity,
|
||||
activity.getString(R.string.hide_manager_toast),
|
||||
activity.getString(R.string.hide_manager_toast2));
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
boolean b = patchAndHide();
|
||||
Data.mainHandler.post(() -> {
|
||||
dialog.cancel();
|
||||
if (!b) {
|
||||
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,197 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.FlashActivity;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.components.BaseActivity;
|
||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||
import com.topjohnwu.magisk.container.Repo;
|
||||
import com.topjohnwu.magisk.utils.Download;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
|
||||
|
||||
private ProgressDialog progressDialog;
|
||||
private boolean mInstall;
|
||||
private File mFile;
|
||||
private Repo mRepo;
|
||||
private int progress = 0, total = -1;
|
||||
|
||||
public ProcessRepoZip(BaseActivity context, Repo repo, boolean install) {
|
||||
super(context);
|
||||
mRepo = repo;
|
||||
mInstall = install && Shell.rootAccess();
|
||||
mFile = new File(Download.EXTERNAL_PATH, repo.getDownloadFilename());
|
||||
}
|
||||
|
||||
private void removeTopFolder(File input, File output) throws IOException {
|
||||
JarEntry entry;
|
||||
try (
|
||||
JarInputStream in = new JarInputStream(new BufferedInputStream(new FileInputStream(input)));
|
||||
JarOutputStream out = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(output)))
|
||||
) {
|
||||
String path;
|
||||
while ((entry = in.getNextJarEntry()) != null) {
|
||||
// Remove the top directory from the path
|
||||
path = entry.getName().substring(entry.getName().indexOf("/") + 1);
|
||||
// If it's the top folder, ignore it
|
||||
if (path.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// Don't include placeholder
|
||||
if (path.equals("system/placeholder")) {
|
||||
continue;
|
||||
}
|
||||
out.putNextEntry(new JarEntry(path));
|
||||
ShellUtils.pump(in, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseActivity getActivity() {
|
||||
return (BaseActivity) super.getActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
BaseActivity activity = getActivity();
|
||||
mFile.getParentFile().mkdirs();
|
||||
progressDialog = ProgressDialog.show(activity, activity.getString(R.string.zip_download_title), activity.getString(R.string.zip_download_msg, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
BaseActivity activity = getActivity();
|
||||
if (activity == null) return null;
|
||||
try {
|
||||
// Request zip from Internet
|
||||
HttpURLConnection conn = WebService.mustRequest(mRepo.getZipUrl(), null);
|
||||
total = conn.getContentLength();
|
||||
|
||||
// Temp files
|
||||
File temp1 = new File(activity.getCacheDir(), "1.zip");
|
||||
File temp2 = new File(temp1.getParentFile(), "2.zip");
|
||||
temp1.getParentFile().mkdir();
|
||||
|
||||
// First download the zip, Web -> temp1
|
||||
try (
|
||||
InputStream in = new BufferedInputStream(new ProgressInputStream(conn.getInputStream()));
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(temp1))
|
||||
) {
|
||||
ShellUtils.pump(in, out);
|
||||
in.close();
|
||||
}
|
||||
conn.disconnect();
|
||||
|
||||
Data.mainHandler.post(() -> {
|
||||
progressDialog.setTitle(R.string.zip_process_title);
|
||||
progressDialog.setMessage(getActivity().getString(R.string.zip_process_msg));
|
||||
});
|
||||
|
||||
// First remove top folder in Github source zip, temp1 -> temp2
|
||||
removeTopFolder(temp1, temp2);
|
||||
|
||||
// Then sign the zip
|
||||
ZipUtils.signZip(temp2, mFile);
|
||||
|
||||
// Delete temp files
|
||||
temp1.delete();
|
||||
temp2.delete();
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
BaseActivity activity = getActivity();
|
||||
if (activity == null) return;
|
||||
progressDialog.dismiss();
|
||||
if (result) {
|
||||
Uri uri = Uri.fromFile(mFile);
|
||||
if (mInstall) {
|
||||
Intent intent = new Intent(activity, Data.classMap.get(FlashActivity.class));
|
||||
intent.setData(uri).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP);
|
||||
activity.startActivity(intent);
|
||||
} else {
|
||||
SnackbarMaker.showUri(activity, uri);
|
||||
}
|
||||
} else {
|
||||
Utils.toast(R.string.process_error, Toast.LENGTH_LONG);
|
||||
}
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exec(Void... voids) {
|
||||
getActivity().runWithPermission(
|
||||
new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, super::exec);
|
||||
}
|
||||
|
||||
private class ProgressInputStream extends FilterInputStream {
|
||||
|
||||
ProgressInputStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
private void updateDlProgress(int step) {
|
||||
progress += step;
|
||||
progressDialog.setMessage(getActivity().getString(R.string.zip_download_msg,
|
||||
(int) (100 * (double) progress / total + 0.5)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read() throws IOException {
|
||||
int b = super.read();
|
||||
if (b > 0) {
|
||||
Data.mainHandler.post(() -> updateDlProgress(1));
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int read(@NonNull byte[] b, int off, int len) throws IOException {
|
||||
int read = super.read(b, off, len);
|
||||
if (read > 0) {
|
||||
Data.mainHandler.post(() -> updateDlProgress(read));
|
||||
}
|
||||
return read;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,159 +0,0 @@
|
||||
package com.topjohnwu.magisk.asyncs;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.container.Repo;
|
||||
import com.topjohnwu.magisk.utils.Logger;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.magisk.utils.WebService;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UpdateRepos {
|
||||
|
||||
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
|
||||
private static final int CORE_POOL_SIZE = Math.max(2, CPU_COUNT - 1);
|
||||
private static final DateFormat dateFormat;
|
||||
|
||||
static {
|
||||
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
private MagiskManager mm;
|
||||
private Set<String> cached;
|
||||
private ExecutorService threadPool;
|
||||
|
||||
public UpdateRepos() {
|
||||
mm = Data.MM();
|
||||
}
|
||||
|
||||
private void waitTasks() {
|
||||
threadPool.shutdown();
|
||||
try {
|
||||
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException ignored) {}
|
||||
}
|
||||
|
||||
private boolean loadJSON(String jsonString) throws JSONException, ParseException {
|
||||
JSONArray jsonArray = new JSONArray(jsonString);
|
||||
|
||||
// Empty page, halt
|
||||
if (jsonArray.length() == 0)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject rawRepo = jsonArray.getJSONObject(i);
|
||||
String id = rawRepo.getString("name");
|
||||
Date date = dateFormat.parse(rawRepo.getString("pushed_at"));
|
||||
threadPool.execute(() -> {
|
||||
Repo repo = mm.repoDB.getRepo(id);
|
||||
try {
|
||||
if (repo == null)
|
||||
repo = new Repo(id);
|
||||
else
|
||||
cached.remove(id);
|
||||
repo.update(date);
|
||||
mm.repoDB.addRepo(repo);
|
||||
} catch (Repo.IllegalRepoException e) {
|
||||
Logger.debug(e.getMessage());
|
||||
mm.repoDB.removeRepo(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We sort repos by last push, which means that we only need to check whether the
|
||||
* first page is updated to determine whether the online repo database is changed
|
||||
*/
|
||||
private boolean loadPage(int page) {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
if (page == 0)
|
||||
header.put(Const.Key.IF_NONE_MATCH, mm.prefs.getString(Const.Key.ETAG_KEY, ""));
|
||||
String url = Utils.fmt(Const.Url.REPO_URL, page + 1);
|
||||
|
||||
try {
|
||||
HttpURLConnection conn = WebService.request(url, header);
|
||||
// No updates
|
||||
if (conn.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED)
|
||||
return false;
|
||||
// Current page is the last page
|
||||
if (!loadJSON(WebService.getString(conn)))
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
// Should not happen, but if exception occurs, page load fails
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update ETAG
|
||||
if (page == 0) {
|
||||
String etag = header.get(Const.Key.ETAG_KEY);
|
||||
etag = etag.substring(etag.indexOf('\"'), etag.lastIndexOf('\"') + 1);
|
||||
mm.prefs.edit().putString(Const.Key.ETAG_KEY, etag).apply();
|
||||
}
|
||||
|
||||
String links = header.get(Const.Key.LINK_KEY);
|
||||
return links == null || !links.contains("next") || loadPage(page + 1);
|
||||
}
|
||||
|
||||
private void fullReload() {
|
||||
Cursor c = mm.repoDB.getRawCursor();
|
||||
while (c.moveToNext()) {
|
||||
Repo repo = new Repo(c);
|
||||
threadPool.execute(() -> {
|
||||
try {
|
||||
repo.update();
|
||||
mm.repoDB.addRepo(repo);
|
||||
} catch (Repo.IllegalRepoException e) {
|
||||
Logger.debug(e.getMessage());
|
||||
mm.repoDB.removeRepo(repo);
|
||||
}
|
||||
});
|
||||
}
|
||||
waitTasks();
|
||||
}
|
||||
|
||||
public void exec(boolean force) {
|
||||
Topic.reset(Topic.REPO_LOAD_DONE);
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
cached = Collections.synchronizedSet(mm.repoDB.getRepoIDSet());
|
||||
threadPool = Executors.newFixedThreadPool(CORE_POOL_SIZE);
|
||||
|
||||
if (loadPage(0)) {
|
||||
waitTasks();
|
||||
// The leftover cached means they are removed from online repo
|
||||
mm.repoDB.removeRepo(cached);
|
||||
} else if (force) {
|
||||
fullReload();
|
||||
}
|
||||
Topic.publish(Topic.REPO_LOAD_DONE);
|
||||
});
|
||||
}
|
||||
|
||||
public void exec() {
|
||||
exec(false);
|
||||
}
|
||||
}
|
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 dvdandroid
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
|
||||
import butterknife.BindView;
|
||||
|
||||
/**
|
||||
* @author dvdandroid
|
||||
*/
|
||||
public class AboutCardRow extends LinearLayout {
|
||||
|
||||
@BindView(android.R.id.title) TextView mTitle;
|
||||
@BindView(android.R.id.summary) TextView mSummary;
|
||||
@BindView(android.R.id.icon) ImageView mIcon;
|
||||
@BindView(R.id.container) View mView;
|
||||
|
||||
public AboutCardRow(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public AboutCardRow(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public AboutCardRow(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
LayoutInflater.from(context).inflate(R.layout.info_item_row, this);
|
||||
new AboutCardRow_ViewBinding(this, this);
|
||||
|
||||
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AboutCardRow, 0, 0);
|
||||
String title;
|
||||
Drawable icon;
|
||||
try {
|
||||
title = a.getString(R.styleable.AboutCardRow_text);
|
||||
icon = a.getDrawable(R.styleable.AboutCardRow_icon);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
mTitle.setText(title);
|
||||
mIcon.setImageDrawable(icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnClickListener(OnClickListener l) {
|
||||
mView.setOnClickListener(l);
|
||||
}
|
||||
|
||||
public void setSummary(String s) {
|
||||
mSummary.setVisibility(VISIBLE);
|
||||
mSummary.setText(s);
|
||||
}
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import butterknife.Unbinder;
|
||||
|
||||
public class BaseFragment extends Fragment implements Topic.AutoSubscriber {
|
||||
|
||||
public MagiskManager mm;
|
||||
protected Unbinder unbinder = null;
|
||||
|
||||
public BaseFragment() {
|
||||
mm = Data.MM();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Topic.subscribe(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
Topic.unsubscribe(this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
if (unbinder != null)
|
||||
unbinder.unbind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startActivityForResult(Intent intent, int requestCode) {
|
||||
startActivityForResult(intent, requestCode, this::onActivityResult);
|
||||
}
|
||||
|
||||
public void startActivityForResult(Intent intent, int requestCode, BaseActivity.ActivityResultListener listener) {
|
||||
((BaseActivity) requireActivity()).startActivityForResult(intent, requestCode, listener);
|
||||
}
|
||||
|
||||
public void runWithPermission(String[] permissions, Runnable callback) {
|
||||
((BaseActivity) requireActivity()).runWithPermission(permissions,callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSubscribedTopics() {
|
||||
return FlavorActivity.EMPTY_INT_ARRAY;
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.asyncs.InstallMagisk;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class EnvFixDialog extends CustomAlertDialog {
|
||||
|
||||
public EnvFixDialog(@NonNull Activity activity) {
|
||||
super(activity);
|
||||
setTitle(R.string.env_fix_title);
|
||||
setMessage(R.string.env_fix_msg);
|
||||
setCancelable(true);
|
||||
setPositiveButton(R.string.yes, (d, i) -> new InstallMagisk(activity).exec());
|
||||
setNegativeButton(R.string.no_thanks, null);
|
||||
}
|
||||
}
|
@@ -1,84 +0,0 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
public interface ExpandableView {
|
||||
|
||||
class Container {
|
||||
public ViewGroup expandLayout;
|
||||
ValueAnimator expandAnimator, collapseAnimator;
|
||||
boolean mExpanded = false;
|
||||
int expandHeight = 0;
|
||||
}
|
||||
|
||||
// Provide state info
|
||||
Container getContainer();
|
||||
|
||||
default void setupExpandable() {
|
||||
Container container = getContainer();
|
||||
container.expandLayout.getViewTreeObserver().addOnPreDrawListener(
|
||||
new ViewTreeObserver.OnPreDrawListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
if (container.expandHeight == 0) {
|
||||
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
container.expandLayout.measure(widthSpec, heightSpec);
|
||||
container.expandHeight = container.expandLayout.getMeasuredHeight();
|
||||
}
|
||||
|
||||
container.expandLayout.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
container.expandLayout.setVisibility(View.GONE);
|
||||
container.expandAnimator = slideAnimator(0, container.expandHeight);
|
||||
container.collapseAnimator = slideAnimator(container.expandHeight, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
default boolean isExpanded() {
|
||||
return getContainer().mExpanded;
|
||||
}
|
||||
|
||||
default void setExpanded(boolean expanded) {
|
||||
Container container = getContainer();
|
||||
container.mExpanded = expanded;
|
||||
ViewGroup.LayoutParams layoutParams = container.expandLayout.getLayoutParams();
|
||||
layoutParams.height = expanded ? container.expandHeight : 0;
|
||||
container.expandLayout.setLayoutParams(layoutParams);
|
||||
container.expandLayout.setVisibility(expanded ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
default void expand() {
|
||||
Container container = getContainer();
|
||||
if (container.mExpanded) return;
|
||||
container.expandLayout.setVisibility(View.VISIBLE);
|
||||
container.expandAnimator.start();
|
||||
container.mExpanded = true;
|
||||
}
|
||||
|
||||
default void collapse() {
|
||||
Container container = getContainer();
|
||||
if (!container.mExpanded) return;
|
||||
container.collapseAnimator.start();
|
||||
container.mExpanded = false;
|
||||
}
|
||||
|
||||
default ValueAnimator slideAnimator(int start, int end) {
|
||||
Container container = getContainer();
|
||||
ValueAnimator animator = ValueAnimator.ofInt(start, end);
|
||||
|
||||
animator.addUpdateListener(valueAnimator -> {
|
||||
int value = (Integer) valueAnimator.getAnimatedValue();
|
||||
ViewGroup.LayoutParams layoutParams = container.expandLayout.getLayoutParams();
|
||||
layoutParams.height = value;
|
||||
container.expandLayout.setLayoutParams(layoutParams);
|
||||
});
|
||||
return animator;
|
||||
}
|
||||
}
|
@@ -1,88 +0,0 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public abstract class FlavorActivity extends AppCompatActivity implements Topic.AutoSubscriber {
|
||||
|
||||
private ActivityResultListener activityResultListener;
|
||||
static int[] EMPTY_INT_ARRAY = new int[0];
|
||||
public MagiskManager mm;
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
Configuration config = base.getResources().getConfiguration();
|
||||
config.setLocale(LocaleManager.locale);
|
||||
applyOverrideConfiguration(config);
|
||||
mm = Data.MM();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSubscribedTopics() {
|
||||
return EMPTY_INT_ARRAY;
|
||||
}
|
||||
|
||||
@StyleRes
|
||||
public int getDarkTheme() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
Topic.subscribe(this);
|
||||
if (Data.isDarkTheme && getDarkTheme() != -1) {
|
||||
setTheme(getDarkTheme());
|
||||
}
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
Topic.unsubscribe(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
protected void setFloating() {
|
||||
boolean isTablet = getResources().getBoolean(R.bool.isTablet);
|
||||
if (isTablet) {
|
||||
WindowManager.LayoutParams params = getWindow().getAttributes();
|
||||
params.height = getResources().getDimensionPixelSize(R.dimen.floating_height);
|
||||
params.width = getResources().getDimensionPixelSize(R.dimen.floating_width);
|
||||
params.alpha = 1.0f;
|
||||
params.dimAmount = 0.6f;
|
||||
params.flags |= 2;
|
||||
getWindow().setAttributes(params);
|
||||
setFinishOnTouchOutside(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (activityResultListener != null)
|
||||
activityResultListener.onActivityResult(requestCode, resultCode, data);
|
||||
activityResultListener = null;
|
||||
}
|
||||
|
||||
public void startActivityForResult(Intent intent, int requestCode, ActivityResultListener listener) {
|
||||
activityResultListener = listener;
|
||||
super.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
public interface ActivityResultListener {
|
||||
void onActivityResult(int requestCode, int resultCode, Intent data);
|
||||
}
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.FlashActivity;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||
import com.topjohnwu.magisk.utils.Download;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
class InstallMethodDialog extends AlertDialog.Builder {
|
||||
|
||||
InstallMethodDialog(BaseActivity activity, List<String> options) {
|
||||
super(activity);
|
||||
setTitle(R.string.select_method);
|
||||
setItems(options.toArray(new String [0]), (dialog, idx) -> {
|
||||
Intent intent;
|
||||
switch (idx) {
|
||||
case 1:
|
||||
Utils.toast(R.string.boot_file_patch_msg, Toast.LENGTH_LONG);
|
||||
intent = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*");
|
||||
activity.runWithPermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, () ->
|
||||
activity.startActivityForResult(intent, Const.ID.SELECT_BOOT,
|
||||
(requestCode, resultCode, data) -> {
|
||||
if (requestCode == Const.ID.SELECT_BOOT &&
|
||||
resultCode == Activity.RESULT_OK && data != null) {
|
||||
Intent i = new Intent(activity, Data.classMap.get(FlashActivity.class))
|
||||
.putExtra(Const.Key.FLASH_SET_BOOT, data.getData())
|
||||
.putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_BOOT);
|
||||
activity.startActivity(i);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
break;
|
||||
case 0:
|
||||
String filename = Utils.fmt("Magisk-v%s(%d).zip",
|
||||
Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode);
|
||||
Download.receive(activity, new DownloadReceiver() {
|
||||
@Override
|
||||
public void onDownloadDone(Context context, Uri uri) {
|
||||
SnackbarMaker.showUri(activity, uri);
|
||||
}
|
||||
}, Data.magiskLink, filename);
|
||||
break;
|
||||
case 2:
|
||||
intent = new Intent(activity, Data.classMap.get(FlashActivity.class))
|
||||
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_MAGISK);
|
||||
activity.startActivity(intent);
|
||||
break;
|
||||
case 3:
|
||||
new CustomAlertDialog(activity)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.install_inactive_slot_msg)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.yes, (d, i) -> {
|
||||
Intent it = new Intent(activity, Data.classMap.get(FlashActivity.class))
|
||||
.putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_INACTIVE_SLOT);
|
||||
activity.startActivity(it);
|
||||
})
|
||||
.setNegativeButton(R.string.no_thanks, null)
|
||||
.show();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,51 +0,0 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MagiskInstallDialog extends CustomAlertDialog {
|
||||
public MagiskInstallDialog(BaseActivity activity) {
|
||||
super(activity);
|
||||
MagiskManager mm = Data.MM();
|
||||
String filename = Utils.fmt("Magisk-v%s(%d).zip",
|
||||
Data.remoteMagiskVersionString, Data.remoteMagiskVersionCode);
|
||||
setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.magisk)));
|
||||
setMessage(mm.getString(R.string.repo_install_msg, filename));
|
||||
setCancelable(true);
|
||||
setPositiveButton(R.string.install, (d, i) -> {
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add(mm.getString(R.string.download_zip_only));
|
||||
options.add(mm.getString(R.string.patch_boot_file));
|
||||
if (Shell.rootAccess()) {
|
||||
options.add(mm.getString(R.string.direct_install));
|
||||
String s = ShellUtils.fastCmd("grep_prop ro.build.ab_update");
|
||||
if (!s.isEmpty() && Boolean.parseBoolean(s)) {
|
||||
options.add(mm.getString(R.string.install_inactive_slot));
|
||||
}
|
||||
}
|
||||
new InstallMethodDialog(activity, options).show();
|
||||
});
|
||||
setNegativeButton(R.string.no_thanks, null);
|
||||
if (!TextUtils.isEmpty(Data.magiskNoteLink)) {
|
||||
setNeutralButton(R.string.release_notes, (d, i) -> {
|
||||
if (Data.magiskNoteLink.contains("forum.xda-developers")) {
|
||||
// Open forum links in browser
|
||||
Utils.openLink(activity, Uri.parse(Data.magiskNoteLink));
|
||||
} else {
|
||||
new MarkDownWindow(activity, null, Data.magiskNoteLink).exec();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,40 +0,0 @@
|
||||
package com.topjohnwu.magisk.components;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
||||
import com.topjohnwu.magisk.receivers.ManagerUpdate;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class ManagerInstallDialog extends CustomAlertDialog {
|
||||
|
||||
public ManagerInstallDialog(@NonNull BaseActivity activity) {
|
||||
super(activity);
|
||||
MagiskManager mm = Data.MM();
|
||||
String filename = Utils.fmt("MagiskManager-v%s(%d).apk",
|
||||
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
||||
setTitle(mm.getString(R.string.repo_install_title, mm.getString(R.string.app_name)));
|
||||
setMessage(mm.getString(R.string.repo_install_msg, filename));
|
||||
setCancelable(true);
|
||||
setPositiveButton(R.string.install, (d, i) -> activity.runWithPermission(
|
||||
new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, () -> {
|
||||
Intent intent = new Intent(mm, Data.classMap.get(ManagerUpdate.class));
|
||||
intent.putExtra(Const.Key.INTENT_SET_LINK, Data.managerLink);
|
||||
intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename);
|
||||
mm.sendBroadcast(intent);
|
||||
}))
|
||||
.setNegativeButton(R.string.no_thanks, null);
|
||||
if (!TextUtils.isEmpty(Data.managerNoteLink)) {
|
||||
setNeutralButton(R.string.app_changelog, (d, i) ->
|
||||
new MarkDownWindow(activity, null, Data.managerNoteLink).exec());
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
package com.topjohnwu.magisk.container;
|
||||
|
||||
import org.kamranzafar.jtar.TarHeader;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TarEntry extends org.kamranzafar.jtar.TarEntry {
|
||||
|
||||
public TarEntry(File file, String entryName) {
|
||||
super(file, entryName);
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround missing java.nio.file.attribute.PosixFilePermission
|
||||
* Simply just assign a default permission to the file
|
||||
* */
|
||||
|
||||
@Override
|
||||
public void extractTarHeader(String entryName) {
|
||||
int permissions = file.isDirectory() ? 000755 : 000644;
|
||||
header = TarHeader.createHeader(entryName, file.length(), file.lastModified() / 1000, file.isDirectory(), permissions);
|
||||
header.userName = new StringBuffer("");
|
||||
header.groupName = header.userName;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewrite the header to GNU format
|
||||
* */
|
||||
|
||||
@Override
|
||||
public void writeEntryHeader(byte[] outbuf) {
|
||||
super.writeEntryHeader(outbuf);
|
||||
|
||||
System.arraycopy("ustar \0".getBytes(), 0, outbuf, 257, TarHeader.USTAR_MAGICLEN);
|
||||
getOctalBytes(header.mode, outbuf, 100, TarHeader.MODELEN);
|
||||
getOctalBytes(header.userId, outbuf, 108, TarHeader.UIDLEN);
|
||||
getOctalBytes(header.groupId, outbuf, 116, TarHeader.GIDLEN);
|
||||
getOctalBytes(header.size, outbuf, 124, TarHeader.SIZELEN);
|
||||
getOctalBytes(header.modTime, outbuf, 136, TarHeader.MODTIMELEN);
|
||||
Arrays.fill(outbuf, 148, 148 + TarHeader.CHKSUMLEN, (byte) ' ');
|
||||
Arrays.fill(outbuf, 329, 329 + TarHeader.USTAR_DEVLEN, (byte) '\0');
|
||||
Arrays.fill(outbuf, 337, 337 + TarHeader.USTAR_DEVLEN, (byte) '\0');
|
||||
|
||||
// Recalculate checksum
|
||||
getOctalBytes(computeCheckSum(outbuf), outbuf, 148, TarHeader.CHKSUMLEN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Proper octal to ASCII conversion
|
||||
* */
|
||||
|
||||
private void getOctalBytes(long value, byte[] buf, int offset, int length) {
|
||||
int idx = length - 1;
|
||||
|
||||
buf[offset + idx] = 0;
|
||||
--idx;
|
||||
|
||||
for (long val = value; idx >= 0; --idx) {
|
||||
buf[offset + idx] = (byte) ((byte) '0' + (byte) (val & 7));
|
||||
val = val >> 3;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,311 +0,0 @@
|
||||
package com.topjohnwu.magisk.database;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.container.Policy;
|
||||
import com.topjohnwu.magisk.container.SuLogEntry;
|
||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.DateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class MagiskDatabaseHelper {
|
||||
|
||||
private static final int DATABASE_VER = 6;
|
||||
private static final int OLD_DATABASE_VER = 5;
|
||||
private static final String POLICY_TABLE = "policies";
|
||||
private static final String LOG_TABLE = "logs";
|
||||
private static final String SETTINGS_TABLE = "settings";
|
||||
private static final String STRINGS_TABLE = "strings";
|
||||
private static final File MANAGER_DB =
|
||||
new File(Utils.fmt("/sbin/.core/db-%d/magisk.db", Const.USER_ID));
|
||||
|
||||
private PackageManager pm;
|
||||
private SQLiteDatabase db;
|
||||
|
||||
@NonNull
|
||||
public static MagiskDatabaseHelper getInstance() {
|
||||
try {
|
||||
return new MagiskDatabaseHelper();
|
||||
} catch (Exception e) {
|
||||
// Let's cleanup everything and try again
|
||||
Shell.su("db_clean '*'").exec();
|
||||
return new MagiskDatabaseHelper();
|
||||
}
|
||||
}
|
||||
|
||||
private MagiskDatabaseHelper() {
|
||||
pm = Data.MM().getPackageManager();
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
db = openDatabase();
|
||||
db.disableWriteAheadLogging();
|
||||
int version = Data.magiskVersionCode >= Const.MAGISK_VER.DBVER_SIX ? DATABASE_VER : OLD_DATABASE_VER;
|
||||
int curVersion = db.getVersion();
|
||||
if (curVersion < version) {
|
||||
onUpgrade(db, curVersion);
|
||||
} else if (curVersion > DATABASE_VER) {
|
||||
/* Higher than we can possibly support */
|
||||
onDowngrade(db);
|
||||
}
|
||||
db.setVersion(version);
|
||||
clearOutdated();
|
||||
}
|
||||
|
||||
private SQLiteDatabase openDatabase() {
|
||||
MagiskManager mm = Data.MM();
|
||||
Context de = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
|
||||
? mm.createDeviceProtectedStorageContext() : mm;
|
||||
if (!MANAGER_DB.canWrite()) {
|
||||
if (!Shell.rootAccess()) {
|
||||
// We don't want the app to crash, create a db and return
|
||||
return mm.openOrCreateDatabase("su.db", Context.MODE_PRIVATE, null);
|
||||
}
|
||||
// Cleanup
|
||||
Shell.su("db_clean " + Const.USER_ID).exec();
|
||||
// Global database
|
||||
final SuFile GLOBAL_DB = new SuFile("/data/adb/magisk.db");
|
||||
mm.deleteDatabase("su.db");
|
||||
de.deleteDatabase("su.db");
|
||||
if (Data.magiskVersionCode < Const.MAGISK_VER.SEPOL_REFACTOR) {
|
||||
// We need some additional policies on old versions
|
||||
Shell.su("db_sepatch").exec();
|
||||
}
|
||||
if (!GLOBAL_DB.exists()) {
|
||||
Shell.su("db_init").exec();
|
||||
SQLiteDatabase.openOrCreateDatabase(GLOBAL_DB, null).close();
|
||||
Shell.su("db_restore").exec();
|
||||
}
|
||||
Shell.su("db_setup " + Process.myUid()).exec();
|
||||
}
|
||||
// Not using legacy mode, open the mounted global DB
|
||||
return SQLiteDatabase.openOrCreateDatabase(MANAGER_DB, null);
|
||||
}
|
||||
|
||||
private void onUpgrade(SQLiteDatabase db, int oldVersion) {
|
||||
if (oldVersion == 0) {
|
||||
createTables(db);
|
||||
oldVersion = 3;
|
||||
}
|
||||
if (oldVersion == 1) {
|
||||
// We're dropping column app_name, rename and re-construct table
|
||||
db.execSQL(Utils.fmt("ALTER TABLE %s RENAME TO %s_old", POLICY_TABLE));
|
||||
|
||||
// Create the new tables
|
||||
createTables(db);
|
||||
|
||||
// Migrate old data to new tables
|
||||
db.execSQL(Utils.fmt("INSERT INTO %s SELECT " +
|
||||
"uid, package_name, policy, until, logging, notification FROM %s_old",
|
||||
POLICY_TABLE, POLICY_TABLE));
|
||||
db.execSQL(Utils.fmt("DROP TABLE %s_old", POLICY_TABLE));
|
||||
|
||||
Data.MM().deleteDatabase("sulog.db");
|
||||
++oldVersion;
|
||||
}
|
||||
if (oldVersion == 2) {
|
||||
db.execSQL(Utils.fmt("UPDATE %s SET time=time*1000", LOG_TABLE));
|
||||
++oldVersion;
|
||||
}
|
||||
if (oldVersion == 3) {
|
||||
db.execSQL(Utils.fmt("CREATE TABLE IF NOT EXISTS %s (key TEXT, value TEXT, PRIMARY KEY(key))", STRINGS_TABLE));
|
||||
++oldVersion;
|
||||
}
|
||||
if (oldVersion == 4) {
|
||||
db.execSQL(Utils.fmt("UPDATE %s SET uid=uid%%100000", POLICY_TABLE));
|
||||
++oldVersion;
|
||||
}
|
||||
if (oldVersion == 5) {
|
||||
setSettings(Const.Key.SU_FINGERPRINT,
|
||||
Data.MM().prefs.getBoolean(Const.Key.SU_FINGERPRINT, false) ? 1 : 0);
|
||||
++oldVersion;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove everything, we do not support downgrade
|
||||
private void onDowngrade(SQLiteDatabase db) {
|
||||
Utils.toast(R.string.su_db_corrupt, Toast.LENGTH_LONG);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + POLICY_TABLE);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + LOG_TABLE);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + SETTINGS_TABLE);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + STRINGS_TABLE);
|
||||
onUpgrade(db, 0);
|
||||
}
|
||||
|
||||
private void createTables(SQLiteDatabase db) {
|
||||
// Policies
|
||||
db.execSQL(
|
||||
"CREATE TABLE IF NOT EXISTS " + POLICY_TABLE + " " +
|
||||
"(uid INT, package_name TEXT, policy INT, " +
|
||||
"until INT, logging INT, notification INT, " +
|
||||
"PRIMARY KEY(uid))");
|
||||
|
||||
// Logs
|
||||
db.execSQL(
|
||||
"CREATE TABLE IF NOT EXISTS " + LOG_TABLE + " " +
|
||||
"(from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " +
|
||||
"to_uid INT, action INT, time INT, command TEXT)");
|
||||
|
||||
// Settings
|
||||
db.execSQL(
|
||||
"CREATE TABLE IF NOT EXISTS " + SETTINGS_TABLE + " " +
|
||||
"(key TEXT, value INT, PRIMARY KEY(key))");
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
db.close();
|
||||
init();
|
||||
}
|
||||
|
||||
public void clearOutdated() {
|
||||
// Clear outdated policies
|
||||
db.delete(POLICY_TABLE, Utils.fmt("until > 0 AND until < %d", System.currentTimeMillis() / 1000), null);
|
||||
// Clear outdated logs
|
||||
db.delete(LOG_TABLE, Utils.fmt("time < %d", System.currentTimeMillis() - Data.suLogTimeout * 86400000), null);
|
||||
}
|
||||
|
||||
public void deletePolicy(Policy policy) {
|
||||
deletePolicy(policy.uid);
|
||||
}
|
||||
|
||||
public void deletePolicy(String pkg) {
|
||||
db.delete(POLICY_TABLE, "package_name=?", new String[] { pkg });
|
||||
}
|
||||
|
||||
public void deletePolicy(int uid) {
|
||||
db.delete(POLICY_TABLE, Utils.fmt("uid=%d", uid), null);
|
||||
}
|
||||
|
||||
public Policy getPolicy(int uid) {
|
||||
Policy policy = null;
|
||||
try (Cursor c = db.query(POLICY_TABLE, null, Utils.fmt("uid=%d", uid), null, null, null, null)) {
|
||||
if (c.moveToNext()) {
|
||||
policy = new Policy(c, pm);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
deletePolicy(uid);
|
||||
return null;
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
||||
public void addPolicy(Policy policy) {
|
||||
db.replace(POLICY_TABLE, null, policy.getContentValues());
|
||||
}
|
||||
|
||||
public void updatePolicy(Policy policy) {
|
||||
db.update(POLICY_TABLE, policy.getContentValues(), Utils.fmt("uid=%d", policy.uid), null);
|
||||
}
|
||||
|
||||
public List<Policy> getPolicyList(PackageManager pm) {
|
||||
try (Cursor c = db.query(POLICY_TABLE, null, Utils.fmt("uid/100000=%d", Const.USER_ID),
|
||||
null, null, null, null)) {
|
||||
List<Policy> ret = new ArrayList<>(c.getCount());
|
||||
while (c.moveToNext()) {
|
||||
try {
|
||||
Policy policy = new Policy(c, pm);
|
||||
ret.add(policy);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// The app no longer exist, remove from DB
|
||||
deletePolicy(c.getInt(c.getColumnIndex("uid")));
|
||||
}
|
||||
}
|
||||
Collections.sort(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public List<List<Integer>> getLogStructure() {
|
||||
try (Cursor c = db.query(LOG_TABLE, new String[] { "time" }, Utils.fmt("from_uid/100000=%d", Const.USER_ID),
|
||||
null, null, null, "time DESC")) {
|
||||
List<List<Integer>> ret = new ArrayList<>();
|
||||
List<Integer> list = null;
|
||||
String dateString = null, newString;
|
||||
while (c.moveToNext()) {
|
||||
Date date = new Date(c.getLong(c.getColumnIndex("time")));
|
||||
newString = DateFormat.getDateInstance(DateFormat.MEDIUM, LocaleManager.locale).format(date);
|
||||
if (!TextUtils.equals(dateString, newString)) {
|
||||
dateString = newString;
|
||||
list = new ArrayList<>();
|
||||
ret.add(list);
|
||||
}
|
||||
list.add(c.getPosition());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public Cursor getLogCursor() {
|
||||
return db.query(LOG_TABLE, null, Utils.fmt("from_uid/100000=%d", Const.USER_ID),
|
||||
null, null, null, "time DESC");
|
||||
}
|
||||
|
||||
public void addLog(SuLogEntry log) {
|
||||
db.insert(LOG_TABLE, null, log.getContentValues());
|
||||
}
|
||||
|
||||
public void clearLogs() {
|
||||
db.delete(LOG_TABLE, null, null);
|
||||
}
|
||||
|
||||
public void setSettings(String key, int value) {
|
||||
ContentValues data = new ContentValues();
|
||||
data.put("key", key);
|
||||
data.put("value", value);
|
||||
db.replace(SETTINGS_TABLE, null, data);
|
||||
}
|
||||
|
||||
public int getSettings(String key, int defaultValue) {
|
||||
int value = defaultValue;
|
||||
try (Cursor c = db.query(SETTINGS_TABLE, null, "key=?",new String[] { key }, null, null, null)) {
|
||||
if (c.moveToNext()) {
|
||||
value = c.getInt(c.getColumnIndex("value"));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setStrings(String key, String value) {
|
||||
if (value == null) {
|
||||
db.delete(STRINGS_TABLE, "key=?", new String[] { key });
|
||||
} else {
|
||||
ContentValues data = new ContentValues();
|
||||
data.put("key", key);
|
||||
data.put("value", value);
|
||||
db.replace(STRINGS_TABLE, null, data);
|
||||
}
|
||||
}
|
||||
|
||||
public String getStrings(String key, String defaultValue) {
|
||||
String value = defaultValue;
|
||||
try (Cursor c = db.query(STRINGS_TABLE, null, "key=?",new String[] { key }, null, null, null)) {
|
||||
if (c.moveToNext()) {
|
||||
value = c.getString(c.getColumnIndex("value"));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
@@ -1,314 +0,0 @@
|
||||
package com.topjohnwu.magisk.fragments;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.BuildConfig;
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MainActivity;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.asyncs.CheckSafetyNet;
|
||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||
import com.topjohnwu.magisk.components.BaseActivity;
|
||||
import com.topjohnwu.magisk.components.BaseFragment;
|
||||
import com.topjohnwu.magisk.components.CustomAlertDialog;
|
||||
import com.topjohnwu.magisk.components.EnvFixDialog;
|
||||
import com.topjohnwu.magisk.components.ExpandableView;
|
||||
import com.topjohnwu.magisk.components.MagiskInstallDialog;
|
||||
import com.topjohnwu.magisk.components.ManagerInstallDialog;
|
||||
import com.topjohnwu.magisk.components.UninstallDialog;
|
||||
import com.topjohnwu.magisk.utils.Download;
|
||||
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import butterknife.BindColor;
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
|
||||
public class MagiskFragment extends BaseFragment
|
||||
implements SwipeRefreshLayout.OnRefreshListener, ExpandableView, Topic.Subscriber {
|
||||
|
||||
private Container expandableContainer = new Container();
|
||||
private static boolean shownDialog = false;
|
||||
|
||||
@BindView(R.id.swipeRefreshLayout) public SwipeRefreshLayout mSwipeRefreshLayout;
|
||||
|
||||
@BindView(R.id.core_only_notice) CardView coreOnlyNotice;
|
||||
|
||||
@BindView(R.id.magisk_update) RelativeLayout magiskUpdate;
|
||||
@BindView(R.id.magisk_update_icon) ImageView magiskUpdateIcon;
|
||||
@BindView(R.id.magisk_update_status) TextView magiskUpdateText;
|
||||
@BindView(R.id.magisk_update_progress) ProgressBar magiskUpdateProgress;
|
||||
@BindView(R.id.magisk_status_icon) ImageView magiskStatusIcon;
|
||||
@BindView(R.id.magisk_version) TextView magiskVersionText;
|
||||
|
||||
@BindView(R.id.safetyNet_card) CardView safetyNetCard;
|
||||
@BindView(R.id.safetyNet_refresh) ImageView safetyNetRefreshIcon;
|
||||
@BindView(R.id.safetyNet_status) TextView safetyNetStatusText;
|
||||
@BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress;
|
||||
@BindView(R.id.expand_layout) LinearLayout expandLayout;
|
||||
@BindView(R.id.cts_status_icon) ImageView ctsStatusIcon;
|
||||
@BindView(R.id.cts_status) TextView ctsStatusText;
|
||||
@BindView(R.id.basic_status_icon) ImageView basicStatusIcon;
|
||||
@BindView(R.id.basic_status) TextView basicStatusText;
|
||||
|
||||
@BindView(R.id.install_option_card) CardView installOptionCard;
|
||||
@BindView(R.id.keep_force_enc) CheckBox keepEncChkbox;
|
||||
@BindView(R.id.keep_verity) CheckBox keepVerityChkbox;
|
||||
@BindView(R.id.install_button) CardView installButton;
|
||||
@BindView(R.id.install_text) TextView installText;
|
||||
@BindView(R.id.uninstall_button) CardView uninstallButton;
|
||||
|
||||
@BindColor(R.color.red500) int colorBad;
|
||||
@BindColor(R.color.green500) int colorOK;
|
||||
@BindColor(R.color.yellow500) int colorWarn;
|
||||
@BindColor(R.color.green500) int colorNeutral;
|
||||
@BindColor(R.color.blue500) int colorInfo;
|
||||
|
||||
@OnClick(R.id.safetyNet_title)
|
||||
void safetyNet() {
|
||||
Runnable task = () -> {
|
||||
safetyNetProgress.setVisibility(View.VISIBLE);
|
||||
safetyNetRefreshIcon.setVisibility(View.GONE);
|
||||
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
|
||||
new CheckSafetyNet(requireActivity()).exec();
|
||||
collapse();
|
||||
};
|
||||
if (!CheckSafetyNet.dexPath.exists()) {
|
||||
// Show dialog
|
||||
new CustomAlertDialog(requireActivity())
|
||||
.setTitle(R.string.proprietary_title)
|
||||
.setMessage(R.string.proprietary_notice)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.yes, (d, i) -> task.run())
|
||||
.setNegativeButton(R.string.no_thanks, null)
|
||||
.show();
|
||||
} else {
|
||||
task.run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@OnClick(R.id.install_button)
|
||||
void install() {
|
||||
shownDialog = true;
|
||||
|
||||
// Show Manager update first
|
||||
if (Data.remoteManagerVersionCode > BuildConfig.VERSION_CODE) {
|
||||
new ManagerInstallDialog((BaseActivity) requireActivity()).show();
|
||||
return;
|
||||
}
|
||||
|
||||
((NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE)).cancelAll();
|
||||
new MagiskInstallDialog((BaseActivity) getActivity()).show();
|
||||
}
|
||||
|
||||
@OnClick(R.id.uninstall_button)
|
||||
void uninstall() {
|
||||
new UninstallDialog(requireActivity()).show();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.fragment_magisk, container, false);
|
||||
unbinder = new MagiskFragment_ViewBinding(this, v);
|
||||
requireActivity().setTitle(R.string.magisk);
|
||||
|
||||
expandableContainer.expandLayout = expandLayout;
|
||||
setupExpandable();
|
||||
|
||||
keepVerityChkbox.setChecked(Data.keepVerity);
|
||||
keepVerityChkbox.setOnCheckedChangeListener((view, checked) -> Data.keepVerity = checked);
|
||||
keepEncChkbox.setChecked(Data.keepEnc);
|
||||
keepEncChkbox.setOnCheckedChangeListener((view, checked) -> Data.keepEnc = checked);
|
||||
|
||||
mSwipeRefreshLayout.setOnRefreshListener(this);
|
||||
updateUI();
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
Data.loadMagiskInfo();
|
||||
updateUI();
|
||||
|
||||
magiskUpdateText.setText(R.string.checking_for_updates);
|
||||
magiskUpdateProgress.setVisibility(View.VISIBLE);
|
||||
magiskUpdateIcon.setVisibility(View.GONE);
|
||||
|
||||
safetyNetStatusText.setText(R.string.safetyNet_check_text);
|
||||
|
||||
Topic.reset(getSubscribedTopics());
|
||||
Data.remoteMagiskVersionString = null;
|
||||
Data.remoteMagiskVersionCode = -1;
|
||||
collapse();
|
||||
|
||||
shownDialog = false;
|
||||
|
||||
// Trigger state check
|
||||
if (Download.checkNetworkStatus(mm)) {
|
||||
CheckUpdates.check();
|
||||
} else {
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSubscribedTopics() {
|
||||
return new int[] {Topic.SNET_CHECK_DONE, Topic.UPDATE_CHECK_DONE};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPublish(int topic, Object[] result) {
|
||||
switch (topic) {
|
||||
case Topic.SNET_CHECK_DONE:
|
||||
updateSafetyNetUI((int) result[0]);
|
||||
break;
|
||||
case Topic.UPDATE_CHECK_DONE:
|
||||
updateCheckUI();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Container getContainer() {
|
||||
return expandableContainer;
|
||||
}
|
||||
|
||||
private boolean hasGms() {
|
||||
PackageManager pm = mm.getPackageManager();
|
||||
PackageInfo info;
|
||||
try {
|
||||
info = pm.getPackageInfo("com.google.android.gms", 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
return info.applicationInfo.enabled;
|
||||
}
|
||||
|
||||
private void updateUI() {
|
||||
((MainActivity) requireActivity()).checkHideSection();
|
||||
|
||||
boolean hasNetwork = Download.checkNetworkStatus(mm);
|
||||
boolean hasRoot = Shell.rootAccess();
|
||||
|
||||
magiskUpdate.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
|
||||
installOptionCard.setVisibility(hasNetwork ? View.VISIBLE : View.GONE);
|
||||
uninstallButton.setVisibility(hasRoot ? View.VISIBLE : View.GONE);
|
||||
coreOnlyNotice.setVisibility(mm.prefs.getBoolean(Const.Key.COREONLY, false) ? View.VISIBLE : View.GONE);
|
||||
|
||||
int image, color;
|
||||
|
||||
if (Data.magiskVersionCode < 0) {
|
||||
color = colorBad;
|
||||
image = R.drawable.ic_cancel;
|
||||
magiskVersionText.setText(R.string.magisk_version_error);
|
||||
} else {
|
||||
color = colorOK;
|
||||
image = R.drawable.ic_check_circle;
|
||||
magiskVersionText.setText(getString(R.string.current_magisk_title, "v" + Data.magiskVersionString));
|
||||
}
|
||||
|
||||
magiskStatusIcon.setImageResource(image);
|
||||
magiskStatusIcon.setColorFilter(color);
|
||||
}
|
||||
|
||||
private void updateCheckUI() {
|
||||
int image, color;
|
||||
|
||||
safetyNetCard.setVisibility(hasGms() ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (Data.remoteMagiskVersionCode < 0) {
|
||||
color = colorNeutral;
|
||||
image = R.drawable.ic_help;
|
||||
magiskUpdateText.setText(R.string.invalid_update_channel);
|
||||
installButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
color = colorOK;
|
||||
image = R.drawable.ic_check_circle;
|
||||
magiskUpdateText.setText(getString(R.string.install_magisk_title, "v" + Data.remoteMagiskVersionString));
|
||||
installButton.setVisibility(View.VISIBLE);
|
||||
if (Data.remoteManagerVersionCode > BuildConfig.VERSION_CODE) {
|
||||
installText.setText(getString(R.string.update, getString(R.string.app_name)));
|
||||
} else if (Data.magiskVersionCode > 0 && Data.remoteMagiskVersionCode > Data.magiskVersionCode) {
|
||||
installText.setText(getString(R.string.update, getString(R.string.magisk)));
|
||||
} else {
|
||||
installText.setText(R.string.install);
|
||||
}
|
||||
}
|
||||
|
||||
magiskUpdateIcon.setImageResource(image);
|
||||
magiskUpdateIcon.setColorFilter(color);
|
||||
magiskUpdateIcon.setVisibility(View.VISIBLE);
|
||||
|
||||
magiskUpdateProgress.setVisibility(View.GONE);
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
|
||||
if (!shownDialog) {
|
||||
if (Data.remoteMagiskVersionCode > Data.magiskVersionCode
|
||||
|| Data.remoteManagerVersionCode > BuildConfig.VERSION_CODE) {
|
||||
install();
|
||||
} else if (Data.remoteMagiskVersionCode >= Const.MAGISK_VER.FIX_ENV &&
|
||||
!ShellUtils.fastCmdResult("env_check")) {
|
||||
new EnvFixDialog(requireActivity()).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSafetyNetUI(int response) {
|
||||
safetyNetProgress.setVisibility(View.GONE);
|
||||
safetyNetRefreshIcon.setVisibility(View.VISIBLE);
|
||||
if ((response & 0x0F) == 0) {
|
||||
safetyNetStatusText.setText(R.string.safetyNet_check_success);
|
||||
|
||||
boolean b;
|
||||
b = (response & ISafetyNetHelper.CTS_PASS) != 0;
|
||||
ctsStatusText.setText("ctsProfile: " + b);
|
||||
ctsStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
|
||||
ctsStatusIcon.setColorFilter(b ? colorOK : colorBad);
|
||||
|
||||
b = (response & ISafetyNetHelper.BASIC_PASS) != 0;
|
||||
basicStatusText.setText("basicIntegrity: " + b);
|
||||
basicStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
|
||||
basicStatusIcon.setColorFilter(b ? colorOK : colorBad);
|
||||
|
||||
expand();
|
||||
} else {
|
||||
@StringRes int resid;
|
||||
switch (response) {
|
||||
case ISafetyNetHelper.RESPONSE_ERR:
|
||||
resid = R.string.safetyNet_res_invalid;
|
||||
break;
|
||||
case ISafetyNetHelper.CONNECTION_FAIL:
|
||||
default:
|
||||
resid = R.string.safetyNet_api_error;
|
||||
break;
|
||||
}
|
||||
safetyNetStatusText.setText(resid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,124 +0,0 @@
|
||||
package com.topjohnwu.magisk.fragments;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.SearchView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.adapters.ReposAdapter;
|
||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||
import com.topjohnwu.magisk.components.BaseFragment;
|
||||
import com.topjohnwu.magisk.container.Module;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
import butterknife.BindView;
|
||||
|
||||
public class ReposFragment extends BaseFragment implements Topic.Subscriber {
|
||||
|
||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||
@BindView(R.id.empty_rv) TextView emptyRv;
|
||||
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
|
||||
|
||||
private ReposAdapter adapter;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_repos, container, false);
|
||||
unbinder = new ReposFragment_ViewBinding(this, view);
|
||||
|
||||
mSwipeRefreshLayout.setRefreshing(true);
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
|
||||
mSwipeRefreshLayout.setOnRefreshListener(() -> {
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
emptyRv.setVisibility(View.GONE);
|
||||
new UpdateRepos().exec(true);
|
||||
});
|
||||
|
||||
requireActivity().setTitle(R.string.downloads);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSubscribedTopics() {
|
||||
return new int[] {Topic.MODULE_LOAD_DONE, Topic.REPO_LOAD_DONE};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPublish(int topic, Object[] result) {
|
||||
if (topic == Topic.MODULE_LOAD_DONE) {
|
||||
adapter = new ReposAdapter(mm.repoDB, (Map<String, Module>) result[0]);
|
||||
mm.repoDB.registerAdapter(adapter);
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
emptyRv.setVisibility(View.GONE);
|
||||
}
|
||||
if (Topic.isPublished(getSubscribedTopics())) {
|
||||
mSwipeRefreshLayout.setRefreshing(false);
|
||||
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
||||
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.menu_repo, menu);
|
||||
SearchView search = (SearchView) menu.findItem(R.id.repo_search).getActionView();
|
||||
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||
@Override
|
||||
public boolean onQueryTextSubmit(String query) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onQueryTextChange(String newText) {
|
||||
adapter.filter(newText);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.repo_sort) {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle(R.string.sorting_order)
|
||||
.setSingleChoiceItems(R.array.sorting_orders, Data.repoOrder, (d, which) -> {
|
||||
Data.repoOrder = which;
|
||||
mm.prefs.edit().putInt(Const.Key.REPO_ORDER, Data.repoOrder).apply();
|
||||
adapter.notifyDBChanged();
|
||||
d.dismiss();
|
||||
}).show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
mm.repoDB.unregisterAdapter();
|
||||
}
|
||||
}
|
@@ -1,342 +0,0 @@
|
||||
package com.topjohnwu.magisk.fragments;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
||||
import com.topjohnwu.magisk.receivers.DownloadReceiver;
|
||||
import com.topjohnwu.magisk.utils.Download;
|
||||
import com.topjohnwu.magisk.utils.FingerprintHelper;
|
||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
||||
import com.topjohnwu.magisk.utils.RootUtils;
|
||||
import com.topjohnwu.magisk.utils.Topic;
|
||||
import com.topjohnwu.magisk.utils.Utils;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceGroupAdapter;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.PreferenceViewHolder;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class SettingsFragment extends PreferenceFragmentCompat
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener,
|
||||
Topic.Subscriber, Topic.AutoSubscriber {
|
||||
|
||||
private PreferenceScreen prefScreen;
|
||||
|
||||
private ListPreference updateChannel, suAccess, autoRes, suNotification,
|
||||
requestTimeout, multiuserMode, namespaceMode;
|
||||
private MagiskManager mm;
|
||||
private PreferenceCategory generalCatagory;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.app_settings, rootKey);
|
||||
mm = Data.MM();
|
||||
prefScreen = getPreferenceScreen();
|
||||
|
||||
generalCatagory = (PreferenceCategory) findPreference("general");
|
||||
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
|
||||
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
|
||||
Preference hideManager = findPreference("hide");
|
||||
Preference restoreManager = findPreference("restore");
|
||||
findPreference("clear").setOnPreferenceClickListener((pref) -> {
|
||||
mm.prefs.edit().remove(Const.Key.ETAG_KEY).apply();
|
||||
mm.repoDB.clearRepo();
|
||||
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT);
|
||||
return true;
|
||||
});
|
||||
|
||||
updateChannel = (ListPreference) findPreference(Const.Key.UPDATE_CHANNEL);
|
||||
suAccess = (ListPreference) findPreference(Const.Key.ROOT_ACCESS);
|
||||
autoRes = (ListPreference) findPreference(Const.Key.SU_AUTO_RESPONSE);
|
||||
requestTimeout = (ListPreference) findPreference(Const.Key.SU_REQUEST_TIMEOUT);
|
||||
suNotification = (ListPreference) findPreference(Const.Key.SU_NOTIFICATION);
|
||||
multiuserMode = (ListPreference) findPreference(Const.Key.SU_MULTIUSER_MODE);
|
||||
namespaceMode = (ListPreference) findPreference(Const.Key.SU_MNT_NS);
|
||||
SwitchPreference reauth = (SwitchPreference) findPreference(Const.Key.SU_REAUTH);
|
||||
SwitchPreference fingerprint = (SwitchPreference) findPreference(Const.Key.SU_FINGERPRINT);
|
||||
|
||||
updateChannel.setOnPreferenceChangeListener((p, o) -> {
|
||||
String prev =String.valueOf(Data.updateChannel);
|
||||
int channel = Integer.parseInt((String) o);
|
||||
if (channel == Const.Value.CUSTOM_CHANNEL) {
|
||||
View v = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_channel_dialog, null);
|
||||
EditText url = v.findViewById(R.id.custom_url);
|
||||
url.setText(mm.prefs.getString(Const.Key.CUSTOM_CHANNEL, ""));
|
||||
new AlertDialog.Builder(requireActivity())
|
||||
.setTitle(R.string.settings_update_custom)
|
||||
.setView(v)
|
||||
.setPositiveButton(R.string.ok, (d, i) ->
|
||||
mm.prefs.edit().putString(Const.Key.CUSTOM_CHANNEL,
|
||||
url.getText().toString()).apply())
|
||||
.setNegativeButton(R.string.close, (d, i) ->
|
||||
mm.prefs.edit().putString(Const.Key.UPDATE_CHANNEL, prev).apply())
|
||||
.setOnCancelListener(d ->
|
||||
mm.prefs.edit().putString(Const.Key.UPDATE_CHANNEL, prev).apply())
|
||||
.show();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
setSummary();
|
||||
|
||||
// Disable dangerous settings in secondary user
|
||||
if (Const.USER_ID > 0) {
|
||||
suCategory.removePreference(multiuserMode);
|
||||
}
|
||||
|
||||
// Disable re-authentication option on Android O, it will not work
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
reauth.setEnabled(false);
|
||||
reauth.setChecked(false);
|
||||
reauth.setSummary(R.string.android_o_not_support);
|
||||
}
|
||||
|
||||
// Disable fingerprint option if not possible
|
||||
if (!FingerprintHelper.canUseFingerprint()) {
|
||||
fingerprint.setEnabled(false);
|
||||
fingerprint.setChecked(false);
|
||||
fingerprint.setSummary(R.string.disable_fingerprint);
|
||||
}
|
||||
|
||||
if (Shell.rootAccess()) {
|
||||
if (mm.getPackageName().equals(Const.ORIG_PKG_NAME)) {
|
||||
hideManager.setOnPreferenceClickListener((pref) -> {
|
||||
PatchAPK.hideManager(requireActivity());
|
||||
return true;
|
||||
});
|
||||
generalCatagory.removePreference(restoreManager);
|
||||
} else {
|
||||
if (Download.checkNetworkStatus(mm)) {
|
||||
restoreManager.setOnPreferenceClickListener((pref) -> {
|
||||
Download.receive(
|
||||
requireActivity(), new DownloadReceiver() {
|
||||
@Override
|
||||
public void onDownloadDone(Context context, Uri uri) {
|
||||
Data.exportPrefs();
|
||||
Shell.su("cp " + uri.getPath() + " /data/local/tmp/manager.apk").exec();
|
||||
if (ShellUtils.fastCmdResult("pm install /data/local/tmp/manager.apk")) {
|
||||
Shell.su("rm -f /data/local/tmp/manager.apk").exec();
|
||||
RootUtils.uninstallPkg(context.getPackageName());
|
||||
return;
|
||||
}
|
||||
Shell.su("rm -f /data/local/tmp/manager.apk").exec();
|
||||
}
|
||||
},
|
||||
Data.managerLink,
|
||||
Utils.fmt("MagiskManager-v%s.apk", Data.remoteManagerVersionString)
|
||||
);
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
generalCatagory.removePreference(restoreManager);
|
||||
}
|
||||
generalCatagory.removePreference(hideManager);
|
||||
}
|
||||
} else {
|
||||
generalCatagory.removePreference(restoreManager);
|
||||
generalCatagory.removePreference(hideManager);
|
||||
}
|
||||
|
||||
if (!Shell.rootAccess() || (Const.USER_ID > 0 &&
|
||||
Data.multiuserMode == Const.Value.MULTIUSER_MODE_OWNER_MANAGED)) {
|
||||
prefScreen.removePreference(suCategory);
|
||||
}
|
||||
|
||||
if (!Shell.rootAccess()) {
|
||||
prefScreen.removePreference(magiskCategory);
|
||||
generalCatagory.removePreference(hideManager);
|
||||
}
|
||||
}
|
||||
|
||||
private void setLocalePreference(ListPreference lp) {
|
||||
CharSequence[] entries = new CharSequence[LocaleManager.locales.size() + 1];
|
||||
CharSequence[] entryValues = new CharSequence[LocaleManager.locales.size() + 1];
|
||||
entries[0] = LocaleManager.getString(LocaleManager.defaultLocale, R.string.system_default);
|
||||
entryValues[0] = "";
|
||||
int i = 1;
|
||||
for (Locale locale : LocaleManager.locales) {
|
||||
entries[i] = locale.getDisplayName(locale);
|
||||
entryValues[i++] = locale.toLanguageTag();
|
||||
}
|
||||
lp.setEntries(entries);
|
||||
lp.setEntryValues(entryValues);
|
||||
lp.setSummary(LocaleManager.locale.getDisplayName(LocaleManager.locale));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
mm.prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
Topic.subscribe(this);
|
||||
requireActivity().setTitle(R.string.settings);
|
||||
return super.onCreateView(inflater, container, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
mm.prefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||
Topic.unsubscribe(this);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
||||
switch (key) {
|
||||
case Const.Key.ROOT_ACCESS:
|
||||
case Const.Key.SU_MULTIUSER_MODE:
|
||||
case Const.Key.SU_MNT_NS:
|
||||
mm.mDB.setSettings(key, Utils.getPrefsInt(prefs, key));
|
||||
break;
|
||||
}
|
||||
Data.loadConfig();
|
||||
setSummary();
|
||||
switch (key) {
|
||||
case Const.Key.DARK_THEME:
|
||||
requireActivity().recreate();
|
||||
break;
|
||||
case Const.Key.COREONLY:
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
try {
|
||||
Const.MAGISK_DISABLE_FILE.createNewFile();
|
||||
} catch (IOException ignored) {}
|
||||
} else {
|
||||
Const.MAGISK_DISABLE_FILE.delete();
|
||||
}
|
||||
Utils.toast(R.string.settings_reboot_toast, Toast.LENGTH_LONG);
|
||||
break;
|
||||
case Const.Key.MAGISKHIDE:
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
Shell.su("magiskhide --enable").submit();
|
||||
} else {
|
||||
Shell.su("magiskhide --disable").submit();
|
||||
}
|
||||
break;
|
||||
case Const.Key.HOSTS:
|
||||
if (prefs.getBoolean(key, false)) {
|
||||
Shell.su("cp -af /system/etc/hosts " + Const.MAGISK_HOST_FILE,
|
||||
"mount -o bind " + Const.MAGISK_HOST_FILE + " /system/etc/hosts")
|
||||
.submit();
|
||||
} else {
|
||||
Shell.su("umount -l /system/etc/hosts",
|
||||
"rm -f " + Const.MAGISK_HOST_FILE)
|
||||
.submit();
|
||||
}
|
||||
break;
|
||||
case Const.Key.LOCALE:
|
||||
LocaleManager.setLocale(mm);
|
||||
requireActivity().recreate();
|
||||
break;
|
||||
case Const.Key.UPDATE_CHANNEL:
|
||||
case Const.Key.CUSTOM_CHANNEL:
|
||||
CheckUpdates.check();
|
||||
break;
|
||||
case Const.Key.CHECK_UPDATES:
|
||||
Utils.setupUpdateCheck();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(Preference preference) {
|
||||
String key = preference.getKey();
|
||||
switch (key) {
|
||||
case Const.Key.SU_FINGERPRINT:
|
||||
boolean checked = ((SwitchPreference) preference).isChecked();
|
||||
((SwitchPreference) preference).setChecked(!checked);
|
||||
FingerprintHelper.showAuthDialog(requireActivity(), () -> {
|
||||
((SwitchPreference) preference).setChecked(checked);
|
||||
Data.suFingerprint = checked;
|
||||
mm.mDB.setSettings(key, checked ? 1 : 0);
|
||||
});
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setSummary() {
|
||||
updateChannel.setSummary(getResources()
|
||||
.getStringArray(R.array.update_channel)[Data.updateChannel]);
|
||||
suAccess.setSummary(getResources()
|
||||
.getStringArray(R.array.su_access)[Data.suAccessState]);
|
||||
autoRes.setSummary(getResources()
|
||||
.getStringArray(R.array.auto_response)[Data.suResponseType]);
|
||||
suNotification.setSummary(getResources()
|
||||
.getStringArray(R.array.su_notification)[Data.suNotificationType]);
|
||||
requestTimeout.setSummary(
|
||||
getString(R.string.request_timeout_summary,
|
||||
mm.prefs.getString(Const.Key.SU_REQUEST_TIMEOUT, "10")));
|
||||
multiuserMode.setSummary(getResources()
|
||||
.getStringArray(R.array.multiuser_summary)[Data.multiuserMode]);
|
||||
namespaceMode.setSummary(getResources()
|
||||
.getStringArray(R.array.namespace_summary)[Data.suNamespaceMode]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPublish(int topic, Object[] result) {
|
||||
setLocalePreference((ListPreference) findPreference(Const.Key.LOCALE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSubscribedTopics() {
|
||||
return new int[] {Topic.LOCALE_FETCH_DONE};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
|
||||
return new PreferenceGroupAdapter(preferenceScreen) {
|
||||
@SuppressLint("RestrictedApi")
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder, int position) {
|
||||
super.onBindViewHolder(holder, position);
|
||||
Preference preference = getItem(position);
|
||||
if (preference instanceof PreferenceCategory)
|
||||
setZeroPaddingToLayoutChildren(holder.itemView);
|
||||
else {
|
||||
View iconFrame = holder.itemView.findViewById(R.id.icon_frame);
|
||||
if (iconFrame != null) {
|
||||
iconFrame.setVisibility(preference.getIcon() == null ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setZeroPaddingToLayoutChildren(View view) {
|
||||
if (!(view instanceof ViewGroup))
|
||||
return;
|
||||
ViewGroup viewGroup = (ViewGroup) view;
|
||||
int childCount = viewGroup.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
setZeroPaddingToLayoutChildren(viewGroup.getChildAt(i));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
viewGroup.setPaddingRelative(0, viewGroup.getPaddingTop(), viewGroup.getPaddingEnd(), viewGroup.getPaddingBottom());
|
||||
else
|
||||
viewGroup.setPadding(0, viewGroup.getPaddingTop(), viewGroup.getPaddingRight(), viewGroup.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
package com.topjohnwu.magisk.receivers;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.SuRequestActivity;
|
||||
import com.topjohnwu.magisk.services.OnBootService;
|
||||
import com.topjohnwu.magisk.utils.SuConnector;
|
||||
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (TextUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED)) {
|
||||
switch (intent.getExtras().getString("action", "boot")) {
|
||||
case "request":
|
||||
Intent i = new Intent(context, Data.classMap.get(SuRequestActivity.class))
|
||||
.putExtra("socket", intent.getStringExtra("socket"))
|
||||
.putExtra("version", 2)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(i);
|
||||
break;
|
||||
case "log":
|
||||
SuConnector.handleLogs(intent, 2);
|
||||
break;
|
||||
case "boot":
|
||||
OnBootService.enqueueWork(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
package com.topjohnwu.magisk.receivers;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.asyncs.PatchAPK;
|
||||
import com.topjohnwu.magisk.utils.Download;
|
||||
import com.topjohnwu.utils.JarMap;
|
||||
import com.topjohnwu.utils.SignAPK;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
||||
public class ManagerUpdate extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Download.receive(
|
||||
context, new PatchedInstall(),
|
||||
intent.getStringExtra(Const.Key.INTENT_SET_LINK),
|
||||
intent.getStringExtra(Const.Key.INTENT_SET_FILENAME)
|
||||
);
|
||||
}
|
||||
|
||||
private static class PatchedInstall extends ManagerInstall {
|
||||
@Override
|
||||
public void onDownloadDone(Context context, Uri uri) {
|
||||
if (!context.getPackageName().equals(Const.ORIG_PKG_NAME)) {
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
String orig = uri.getPath();
|
||||
String patch = orig.substring(0, orig.lastIndexOf('.')) + "-patched.apk";
|
||||
try {
|
||||
JarMap apk = new JarMap(orig);
|
||||
PatchAPK.patchPackageID(apk, Const.ORIG_PKG_NAME, context.getPackageName());
|
||||
SignAPK.sign(apk, new BufferedOutputStream(new FileOutputStream(patch)));
|
||||
super.onDownloadDone(context, Uri.fromFile(new File(patch)));
|
||||
} catch (Exception ignored) { }
|
||||
});
|
||||
} else {
|
||||
super.onDownloadDone(context, uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,32 +0,0 @@
|
||||
package com.topjohnwu.magisk.receivers;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
public class PackageReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
MagiskManager mm = Data.MM();
|
||||
|
||||
String pkg = intent.getData().getEncodedSchemeSpecificPart();
|
||||
|
||||
switch (intent.getAction()) {
|
||||
case Intent.ACTION_PACKAGE_REPLACED:
|
||||
// This will only work pre-O
|
||||
if (mm.prefs.getBoolean(Const.Key.SU_REAUTH, false)) {
|
||||
mm.mDB.deletePolicy(pkg);
|
||||
}
|
||||
break;
|
||||
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
|
||||
mm.mDB.deletePolicy(pkg);
|
||||
Shell.su("magiskhide --rm " + pkg).submit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
package com.topjohnwu.magisk.receivers;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
public class RebootReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Shell.su("/system/bin/reboot").submit();
|
||||
}
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
package com.topjohnwu.magisk.services;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.utils.NotificationMgr;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.JobIntentService;
|
||||
|
||||
public class OnBootService extends JobIntentService {
|
||||
|
||||
public static void enqueueWork(Context context) {
|
||||
enqueueWork(context, Data.classMap.get(OnBootService.class), Const.ID.ONBOOT_SERVICE_ID, new Intent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleWork(@NonNull Intent intent) {
|
||||
/* Devices with DTBO might want to patch dtbo.img.
|
||||
* However, that is not possible if Magisk is installed by
|
||||
* patching boot image with Magisk Manager and flashed via
|
||||
* fastboot, since at that time we do not have root.
|
||||
* Check for dtbo status every boot time, and prompt user
|
||||
* to reboot if dtbo wasn't patched and patched by Magisk Manager.
|
||||
* */
|
||||
if (Shell.rootAccess() && ShellUtils.fastCmdResult("mm_patch_dtbo"))
|
||||
NotificationMgr.dtboPatched();
|
||||
}
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
package com.topjohnwu.magisk.services;
|
||||
|
||||
import android.app.job.JobParameters;
|
||||
import android.app.job.JobService;
|
||||
|
||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
public class UpdateCheckService extends JobService {
|
||||
|
||||
@Override
|
||||
public boolean onStartJob(JobParameters params) {
|
||||
Shell.getShell();
|
||||
CheckUpdates.check(() -> jobFinished(params, false));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onStopJob(JobParameters params) {
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
package com.topjohnwu.magisk.superuser;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.SuRequestActivity;
|
||||
import com.topjohnwu.magisk.components.BaseActivity;
|
||||
|
||||
public class RequestActivity extends BaseActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Intent intent = new Intent(this, Data.classMap.get(SuRequestActivity.class))
|
||||
.putExtra("socket", getIntent().getStringExtra("socket"))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
package com.topjohnwu.magisk.superuser;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.topjohnwu.magisk.utils.SuConnector;
|
||||
|
||||
public class SuReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
SuConnector.handleLogs(intent, 1);
|
||||
}
|
||||
}
|
@@ -1,77 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
public class LocaleManager {
|
||||
public static Locale locale = Locale.getDefault();
|
||||
public final static Locale defaultLocale = Locale.getDefault();
|
||||
public static List<Locale> locales;
|
||||
|
||||
public static void setLocale(MagiskManager mm) {
|
||||
String localeConfig = mm.prefs.getString(Const.Key.LOCALE, "");
|
||||
if (localeConfig.isEmpty()) {
|
||||
locale = defaultLocale;
|
||||
} else {
|
||||
locale = Locale.forLanguageTag(localeConfig);
|
||||
}
|
||||
Locale.setDefault(locale);
|
||||
Resources res = mm.getResources();
|
||||
Configuration config = res.getConfiguration();
|
||||
config.setLocale(locale);
|
||||
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||
}
|
||||
|
||||
public static String getString(Locale locale, @StringRes int id) {
|
||||
Configuration config = new Configuration();
|
||||
config.setLocale(locale);
|
||||
return Data.MM().createConfigurationContext(config).getString(id);
|
||||
}
|
||||
|
||||
public static void loadAvailableLocales() {
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
locales = new ArrayList<>();
|
||||
HashSet<String> set = new HashSet<>();
|
||||
Resources res = Data.MM().getResources();
|
||||
Locale locale;
|
||||
|
||||
@StringRes int compareId = R.string.download_file_error;
|
||||
|
||||
// Add default locale
|
||||
locales.add(Locale.ENGLISH);
|
||||
set.add(getString(Locale.ENGLISH, compareId));
|
||||
|
||||
// Add some special locales
|
||||
locales.add(Locale.TAIWAN);
|
||||
set.add(getString(Locale.TAIWAN, compareId));
|
||||
locale = new Locale("pt", "BR");
|
||||
locales.add(locale);
|
||||
set.add(getString(locale, compareId));
|
||||
|
||||
// Other locales
|
||||
for (String s : res.getAssets().getLocales()) {
|
||||
locale = Locale.forLanguageTag(s);
|
||||
if (set.add(getString(locale, compareId))) {
|
||||
locales.add(locale);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(locales, (a, b) -> a.getDisplayName(a).compareTo(b.getDisplayName(b)));
|
||||
Topic.publish(Topic.LOCALE_FETCH_DONE);
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.SplashActivity;
|
||||
import com.topjohnwu.magisk.receivers.ManagerUpdate;
|
||||
import com.topjohnwu.magisk.receivers.RebootReceiver;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.TaskStackBuilder;
|
||||
|
||||
public class NotificationMgr {
|
||||
|
||||
public static void magiskUpdate() {
|
||||
MagiskManager mm = Data.MM();
|
||||
|
||||
Intent intent = new Intent(mm, Data.classMap.get(SplashActivity.class));
|
||||
intent.putExtra(Const.Key.OPEN_SECTION, "magisk");
|
||||
TaskStackBuilder stackBuilder = TaskStackBuilder.create(mm);
|
||||
stackBuilder.addParentStack(Data.classMap.get(SplashActivity.class));
|
||||
stackBuilder.addNextIntent(intent);
|
||||
PendingIntent pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL);
|
||||
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||
.setContentTitle(mm.getString(R.string.magisk_update_title))
|
||||
.setContentText(mm.getString(R.string.magisk_update_available, Data.remoteMagiskVersionString))
|
||||
.setVibrate(new long[]{0, 100, 100, 100})
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build());
|
||||
}
|
||||
|
||||
public static void managerUpdate() {
|
||||
MagiskManager mm = Data.MM();
|
||||
String filename = Utils.fmt("MagiskManager-v%s(%d).apk",
|
||||
Data.remoteManagerVersionString, Data.remoteManagerVersionCode);
|
||||
|
||||
Intent intent = new Intent(mm, Data.classMap.get(ManagerUpdate.class));
|
||||
intent.putExtra(Const.Key.INTENT_SET_LINK, Data.managerLink);
|
||||
intent.putExtra(Const.Key.INTENT_SET_FILENAME, filename);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(mm,
|
||||
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL);
|
||||
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||
.setContentTitle(mm.getString(R.string.manager_update_title))
|
||||
.setContentText(mm.getString(R.string.manager_download_install))
|
||||
.setVibrate(new long[]{0, 100, 100, 100})
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(pendingIntent);
|
||||
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build());
|
||||
}
|
||||
|
||||
public static void dtboPatched() {
|
||||
MagiskManager mm = Data.MM();
|
||||
|
||||
Intent intent = new Intent(mm, Data.classMap.get(RebootReceiver.class));
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(mm,
|
||||
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(mm, Const.ID.NOTIFICATION_CHANNEL);
|
||||
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||
.setContentTitle(mm.getString(R.string.dtbo_patched_title))
|
||||
.setContentText(mm.getString(R.string.dtbo_patched_reboot))
|
||||
.setVibrate(new long[]{0, 100, 100, 100})
|
||||
.addAction(R.drawable.ic_refresh, mm.getString(R.string.reboot), pendingIntent);
|
||||
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) mm.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build());
|
||||
}
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.superuser.BusyBox;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
import com.topjohnwu.superuser.ShellUtils;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class RootUtils extends Shell.Initializer {
|
||||
|
||||
static {
|
||||
BusyBox.BB_PATH = new File(Const.BUSYBOX_PATH);
|
||||
}
|
||||
|
||||
public static void uninstallPkg(String pkg) {
|
||||
Shell.su("db_clean " + Const.USER_ID, "pm uninstall " + pkg).exec();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInit(Context context, @NonNull Shell shell) {
|
||||
Shell.Job job = shell.newJob();
|
||||
if (shell.isRoot()) {
|
||||
InputStream magiskUtils = context.getResources().openRawResource(R.raw.util_functions);
|
||||
InputStream managerUtils = context.getResources().openRawResource(R.raw.utils);
|
||||
job.add(magiskUtils).add(managerUtils);
|
||||
|
||||
Const.MAGISK_DISABLE_FILE = new SuFile("/cache/.disable_magisk");
|
||||
SuFile file = new SuFile("/sbin/.core/img");
|
||||
if (file.exists()) {
|
||||
Const.MAGISK_PATH = file;
|
||||
} else if ((file = new SuFile("/dev/magisk/img")).exists()) {
|
||||
Const.MAGISK_PATH = file;
|
||||
} else {
|
||||
Const.MAGISK_PATH = new SuFile("/magisk");
|
||||
}
|
||||
Const.MAGISK_HOST_FILE = new SuFile(Const.MAGISK_PATH + "/.core/hosts");
|
||||
|
||||
Data.loadMagiskInfo();
|
||||
} else {
|
||||
InputStream nonroot = context.getResources().openRawResource(R.raw.nonroot_utils);
|
||||
job.add(nonroot);
|
||||
}
|
||||
|
||||
job.add("mount_partitions", "get_flags", "run_migrations", "export BOOTMODE=true").exec();
|
||||
|
||||
Data.keepVerity = Boolean.parseBoolean(ShellUtils.fastCmd("echo $KEEPVERITY"));
|
||||
Data.keepEnc = Boolean.parseBoolean(ShellUtils.fastCmd("echo $KEEPFORCEENCRYPT"));
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -1,118 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.LocalSocket;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.container.Policy;
|
||||
import com.topjohnwu.magisk.container.SuLogEntry;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
public abstract class SuConnector {
|
||||
|
||||
protected LocalSocket socket = new LocalSocket();
|
||||
|
||||
private String readString(DataInputStream is) throws IOException {
|
||||
int len = is.readInt();
|
||||
byte[] buf = new byte[len];
|
||||
is.readFully(buf);
|
||||
return new String(buf);
|
||||
}
|
||||
|
||||
public Bundle readSocketInput() throws IOException {
|
||||
Bundle bundle = new Bundle();
|
||||
DataInputStream is = new DataInputStream(socket.getInputStream());
|
||||
while (true) {
|
||||
String name = readString(is);
|
||||
if (TextUtils.equals(name, "eof"))
|
||||
break;
|
||||
bundle.putString(name, readString(is));
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
protected DataOutputStream getOutputStream() throws IOException {
|
||||
return new DataOutputStream(socket.getOutputStream());
|
||||
}
|
||||
|
||||
public abstract void response();
|
||||
|
||||
public static void handleLogs(Intent intent, int version) {
|
||||
MagiskManager mm = Data.MM();
|
||||
|
||||
if (intent == null) return;
|
||||
|
||||
int fromUid = intent.getIntExtra("from.uid", -1);
|
||||
if (fromUid < 0) return;
|
||||
if (fromUid == Process.myUid()) return;
|
||||
|
||||
Policy policy = mm.mDB.getPolicy(fromUid);
|
||||
if (policy == null) {
|
||||
try {
|
||||
policy = new Policy(fromUid, mm.getPackageManager());
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SuLogEntry log = new SuLogEntry(policy);
|
||||
if (version == 1) {
|
||||
String action = intent.getStringExtra("action");
|
||||
if (action == null) return;
|
||||
switch (action) {
|
||||
case "allow":
|
||||
log.action = true;
|
||||
break;
|
||||
case "deny":
|
||||
log.action = false;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
switch (intent.getIntExtra("policy", -1)) {
|
||||
case Policy.ALLOW:
|
||||
log.action = true;
|
||||
break;
|
||||
case Policy.DENY:
|
||||
log.action = false;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String message = mm.getString(log.action ?
|
||||
R.string.su_allow_toast : R.string.su_deny_toast, policy.appName);
|
||||
|
||||
if (policy.notification && Data.suNotificationType == Const.Value.NOTIFICATION_TOAST)
|
||||
Utils.toast(message, Toast.LENGTH_SHORT);
|
||||
|
||||
if (policy.logging) {
|
||||
int toUid = intent.getIntExtra("to.uid", -1);
|
||||
if (toUid < 0) return;
|
||||
int pid = intent.getIntExtra("pid", -1);
|
||||
if (pid < 0) return;
|
||||
String command = intent.getStringExtra("command");
|
||||
if (command == null) return;
|
||||
log.toUid = toUid;
|
||||
log.fromPid = pid;
|
||||
log.command = command;
|
||||
log.date = new Date();
|
||||
mm.mDB.addLog(log);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,107 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import com.topjohnwu.magisk.Data;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
|
||||
public class Topic {
|
||||
|
||||
public static final int MAGISK_HIDE_DONE = 0;
|
||||
public static final int MODULE_LOAD_DONE = 1;
|
||||
public static final int REPO_LOAD_DONE = 2;
|
||||
public static final int UPDATE_CHECK_DONE = 3;
|
||||
public static final int SNET_CHECK_DONE = 4;
|
||||
public static final int LOCALE_FETCH_DONE = 5;
|
||||
|
||||
@IntDef({MAGISK_HIDE_DONE, MODULE_LOAD_DONE, REPO_LOAD_DONE,
|
||||
UPDATE_CHECK_DONE, SNET_CHECK_DONE, LOCALE_FETCH_DONE})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface TopicID {}
|
||||
|
||||
// We will not dynamically add topics, so use arrays instead of hash tables
|
||||
private static Store[] topicList = new Store[6];
|
||||
|
||||
public static void subscribe(Subscriber sub, @TopicID int... topics) {
|
||||
for (int topic : topics) {
|
||||
if (topicList[topic] == null)
|
||||
topicList[topic] = new Store();
|
||||
topicList[topic].subscribers.add(sub);
|
||||
if (topicList[topic].published) {
|
||||
sub.onPublish(topic, topicList[topic].results);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void subscribe(AutoSubscriber sub) {
|
||||
if (sub instanceof Subscriber)
|
||||
subscribe((Subscriber) sub, sub.getSubscribedTopics());
|
||||
}
|
||||
|
||||
public static void unsubscribe(Subscriber sub, @TopicID int... topics) {
|
||||
for (int topic : topics) {
|
||||
if (topicList[topic] == null)
|
||||
continue;
|
||||
topicList[topic].subscribers.remove(sub);
|
||||
}
|
||||
}
|
||||
|
||||
public static void unsubscribe(AutoSubscriber sub) {
|
||||
if (sub instanceof Subscriber)
|
||||
unsubscribe((Subscriber) sub, sub.getSubscribedTopics());
|
||||
}
|
||||
|
||||
public static void publish(@TopicID int topic, Object... results) {
|
||||
publish(true, topic, results);
|
||||
}
|
||||
|
||||
public static void publish(boolean persist, @TopicID int topic, Object... results) {
|
||||
if (topicList[topic] == null)
|
||||
topicList[topic] = new Store();
|
||||
if (persist) {
|
||||
topicList[topic].results = results;
|
||||
topicList[topic].published = true;
|
||||
}
|
||||
for (Subscriber sub : topicList[topic].subscribers) {
|
||||
Data.mainHandler.post(() -> sub.onPublish(topic, results));
|
||||
}
|
||||
}
|
||||
|
||||
public static void reset(@TopicID int... topics) {
|
||||
for (int topic : topics) {
|
||||
if (topicList[topic] == null)
|
||||
continue;
|
||||
topicList[topic].published = false;
|
||||
topicList[topic].results = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPublished(@TopicID int... topics) {
|
||||
for (int topic : topics) {
|
||||
if (topicList[topic] == null)
|
||||
return false;
|
||||
if (!topicList[topic].published)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class Store {
|
||||
boolean published = false;
|
||||
Set<Subscriber> subscribers = new HashSet<>();
|
||||
Object[] results;
|
||||
}
|
||||
|
||||
public interface Subscriber {
|
||||
void onPublish(int topic, Object[] result);
|
||||
}
|
||||
|
||||
public interface AutoSubscriber {
|
||||
@TopicID
|
||||
int[] getSubscribedTopics();
|
||||
}
|
||||
}
|
@@ -1,143 +0,0 @@
|
||||
package com.topjohnwu.magisk.utils;
|
||||
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.Data;
|
||||
import com.topjohnwu.magisk.MagiskManager;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.container.Module;
|
||||
import com.topjohnwu.magisk.container.ValueSortedMap;
|
||||
import com.topjohnwu.superuser.io.SuFile;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import a.n;
|
||||
|
||||
public class Utils {
|
||||
|
||||
public static int getPrefsInt(SharedPreferences prefs, String key, int def) {
|
||||
return Integer.parseInt(prefs.getString(key, String.valueOf(def)));
|
||||
}
|
||||
|
||||
public static int getPrefsInt(SharedPreferences prefs, String key) {
|
||||
return getPrefsInt(prefs, key, 0);
|
||||
}
|
||||
|
||||
public static String getNameFromUri(Context context, Uri uri) {
|
||||
String name = null;
|
||||
try (Cursor c = context.getContentResolver().query(uri, null, null, null, null)) {
|
||||
if (c != null) {
|
||||
int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
if (nameIndex != -1) {
|
||||
c.moveToFirst();
|
||||
name = c.getString(nameIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (name == null) {
|
||||
int idx = uri.getPath().lastIndexOf('/');
|
||||
name = uri.getPath().substring(idx + 1);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static int dpInPx(int dp) {
|
||||
float scale = Data.MM().getResources().getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5);
|
||||
}
|
||||
|
||||
public static String fmt(String fmt, Object... args) {
|
||||
return String.format(Locale.US, fmt, args);
|
||||
}
|
||||
|
||||
public static String dos2unix(String s) {
|
||||
String newString = s.replace("\r\n", "\n");
|
||||
if(!newString.endsWith("\n")) {
|
||||
return newString + "\n";
|
||||
} else {
|
||||
return newString;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setupUpdateCheck() {
|
||||
MagiskManager mm = Data.MM();
|
||||
JobScheduler scheduler = (JobScheduler) mm.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
|
||||
if (mm.prefs.getBoolean(Const.Key.CHECK_UPDATES, true)) {
|
||||
if (scheduler.getAllPendingJobs().isEmpty() ||
|
||||
Const.UPDATE_SERVICE_VER > mm.prefs.getInt(Const.Key.UPDATE_SERVICE_VER, -1)) {
|
||||
ComponentName service = new ComponentName(mm, n.class);
|
||||
JobInfo info = new JobInfo.Builder(Const.ID.UPDATE_SERVICE_ID, service)
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
|
||||
.setPersisted(true)
|
||||
.setPeriodic(8 * 60 * 60 * 1000)
|
||||
.build();
|
||||
scheduler.schedule(info);
|
||||
}
|
||||
} else {
|
||||
scheduler.cancel(Const.UPDATE_SERVICE_VER);
|
||||
}
|
||||
}
|
||||
|
||||
public static void openLink(Context context, Uri link) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, link);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
if (intent.resolveActivity(context.getPackageManager()) != null) {
|
||||
context.startActivity(intent);
|
||||
} else {
|
||||
toast(R.string.open_link_failed_toast, Toast.LENGTH_SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
public static void toast(CharSequence msg, int duration) {
|
||||
Data.mainHandler.post(() -> Toast.makeText(Data.MM(), msg, duration).show());
|
||||
}
|
||||
|
||||
public static void toast(int resId, int duration) {
|
||||
Data.mainHandler.post(() -> Toast.makeText(Data.MM(), resId, duration).show());
|
||||
}
|
||||
|
||||
public static void loadModules() {
|
||||
Topic.reset(Topic.MODULE_LOAD_DONE);
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
Map<String, Module> moduleMap = new ValueSortedMap<>();
|
||||
SuFile path = new SuFile(Const.MAGISK_PATH);
|
||||
String[] modules = path.list(
|
||||
(file, name) -> !name.equals("lost+found") && !name.equals(".core"));
|
||||
for (String name : modules) {
|
||||
Module module = new Module(Const.MAGISK_PATH + "/" + name);
|
||||
moduleMap.put(module.getId(), module);
|
||||
}
|
||||
Topic.publish(Topic.MODULE_LOAD_DONE, moduleMap);
|
||||
});
|
||||
}
|
||||
|
||||
public static String getAppLabel(ApplicationInfo info, PackageManager pm) {
|
||||
try {
|
||||
if (info.labelRes > 0) {
|
||||
Resources res = pm.getResourcesForApplication(info);
|
||||
Configuration config = new Configuration();
|
||||
config.setLocale(LocaleManager.locale);
|
||||
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||
return res.getString(info.labelRes);
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return info.loadLabel(pm).toString();
|
||||
}
|
||||
}
|
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3H6c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5V19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM12,17.5L6.5,12H10v-2h4v2h3.5L12,17.5zM5.12,5l0.81,-1h12l0.94,1H5.12z"/>
|
||||
</vector>
|
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#757575"
|
||||
android:pathData="M11.8,10.9c-2.27,-0.59 -3,-1.2 -3,-2.15 0,-1.09 1.01,-1.85 2.7,-1.85 1.78,0 2.44,0.85 2.5,2.1h2.21c-0.07,-1.72 -1.12,-3.3 -3.21,-3.81V3h-3v2.16c-1.94,0.42 -3.5,1.68 -3.5,3.61 0,2.31 1.91,3.46 4.7,4.13 2.5,0.6 3,1.48 3,2.41 0,0.69 -0.49,1.79 -2.7,1.79 -2.06,0 -2.87,-0.92 -2.98,-2.1h-2.2c0.12,2.19 1.76,3.42 3.68,3.83V21h3v-2.15c1.95,-0.37 3.5,-1.5 3.5,-3.55 0,-2.84 -2.43,-3.81 -4.7,-4.4z"/>
|
||||
</vector>
|
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M13,7h-2v2h2L13,7zM13,11h-2v6h2v-6zM17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14z"/>
|
||||
</vector>
|
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#757575"
|
||||
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
|
||||
</vector>
|
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#757575"
|
||||
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
||||
</vector>
|
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#757575"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2 0,0.68 0.06,1.34 0.14,2L4.26,14zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zM8.03,8L5.08,8c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14L9.66,14c-0.09,-0.66 -0.16,-1.32 -0.16,-2 0,-0.68 0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2 0,0.68 -0.07,1.34 -0.16,2zM14.59,19.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2 0,-0.68 -0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z"/>
|
||||
</vector>
|
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0" >
|
||||
<path
|
||||
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2S10.9,8 12,8zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,10 12,10zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,16 12,16z"
|
||||
android:fillColor="#757575"/>
|
||||
</vector>
|
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#757575"
|
||||
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||
</vector>
|
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#fff"
|
||||
android:pathData="M10,16h4c0.55,0 1,-0.45 1,-1v-3c0,-0.55 -0.45,-1 -1,-1v-1c0,-1.11 -0.9,-2 -2,-2 -1.11,0 -2,0.9 -2,2v1c-0.55,0 -1,0.45 -1,1v3c0,0.55 0.45,1 1,1zM10.8,10c0,-0.66 0.54,-1.2 1.2,-1.2 0.66,0 1.2,0.54 1.2,1.2v1h-2.4v-1zM17,1L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-2 -2,-2zM17,19L7,19L7,5h10v14z"/>
|
||||
</vector>
|
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#fff"
|
||||
android:pathData="M21,10.12h-6.78l2.74,-2.82c-2.73,-2.7 -7.15,-2.8 -9.88,-0.1 -2.73,2.71 -2.73,7.08 0,9.79 2.73,2.71 7.15,2.71 9.88,0C18.32,15.65 19,14.08 19,12.1h2c0,1.98 -0.88,4.55 -2.64,6.29 -3.51,3.48 -9.21,3.48 -12.72,0 -3.5,-3.47 -3.53,-9.11 -0.02,-12.58 3.51,-3.47 9.14,-3.47 12.65,0L21,3v7.12zM12.5,8v4.25l3.5,2.08 -0.72,1.21L11,13V8h1.5z"/>
|
||||
</vector>
|
@@ -1,107 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/toolbar"/>
|
||||
|
||||
<ScrollView
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
tools:ignore="UseCompoundDrawables,ContentDescription">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
style="?attr/cardStyle"
|
||||
app:cardUseCompatPadding="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="72dp"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="72dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/ic_logo"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:text="@string/app_name"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"/>
|
||||
</LinearLayout>
|
||||
|
||||
<a.o
|
||||
android:id="@+id/app_version_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_info_outline"
|
||||
app:text="@string/app_version"/>
|
||||
|
||||
<a.o
|
||||
android:id="@+id/app_changelog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_history"
|
||||
app:text="@string/app_changelog"/>
|
||||
|
||||
<a.o
|
||||
android:id="@+id/app_translators"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_language"
|
||||
app:text="@string/app_translators"/>
|
||||
|
||||
<a.o
|
||||
android:id="@+id/follow_twitter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_twitter"
|
||||
app:text="@string/follow_twitter"/>
|
||||
|
||||
<a.o
|
||||
android:id="@+id/app_source_code"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_github"
|
||||
app:text="@string/app_source_code"/>
|
||||
|
||||
<a.o
|
||||
android:id="@+id/support_thread"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_xda"
|
||||
app:text="@string/support_thread"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/toolbar"/>
|
||||
|
||||
<ScrollView
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
tools:ignore="UseCompoundDrawables,ContentDescription">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
style="?attr/cardStyle"
|
||||
app:cardUseCompatPadding="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:padding="16dp"
|
||||
android:text="@string/donation"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Headline"/>
|
||||
|
||||
<a.o
|
||||
android:id="@+id/paypal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_paypal"
|
||||
app:text="PayPal"/>
|
||||
|
||||
<a.o
|
||||
android:id="@+id/patreon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:icon="@drawable/ic_patreon"
|
||||
app:text="Patreon"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:windowBackground"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/toolbar" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
@@ -1,401 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/swipeRefreshLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/core_only_notice"
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="4dp"
|
||||
app:cardCornerRadius="@dimen/card_corner_radius"
|
||||
app:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:layout_marginTop="12dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toStartOf="@+id/core_only"
|
||||
android:src="@drawable/ic_warning"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/core_only"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center"
|
||||
android:minWidth="225dp"
|
||||
android:padding="6dp"
|
||||
android:text="@string/settings_core_only_title"
|
||||
android:textStyle="bold" />
|
||||
</RelativeLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="4dp"
|
||||
app:cardCornerRadius="@dimen/card_corner_radius"
|
||||
app:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="7dp"
|
||||
android:paddingTop="7dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/magisk_update"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginTop="5dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/magisk_update_icon"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toStartOf="@+id/magisk_update_status"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/magisk_update_progress"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toStartOf="@+id/magisk_update_status" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/magisk_update_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center"
|
||||
android:minWidth="225dp"
|
||||
android:padding="6dp"
|
||||
android:text="@string/checking_for_updates"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/magisk_status_icon"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toStartOf="@+id/magisk_version" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/magisk_version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center"
|
||||
android:minWidth="225dp"
|
||||
android:padding="6dp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/safetyNet_card"
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="gone"
|
||||
app:cardCornerRadius="@dimen/card_corner_radius"
|
||||
app:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/safetyNet_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/safetyNet_refresh"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_margin="15dp"
|
||||
android:layout_toStartOf="@+id/safetyNet_status"
|
||||
android:src="@drawable/ic_refresh" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/safetyNet_check_progress"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_margin="15dp"
|
||||
android:layout_toStartOf="@+id/safetyNet_status"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/safetyNet_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="center"
|
||||
android:minWidth="175dp"
|
||||
android:padding="6dp"
|
||||
android:text="@string/safetyNet_check_text"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/expand_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingStart="10dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cts_status_icon"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="5dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cts_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:minWidth="150dp"
|
||||
android:padding="6dp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/basic_status_icon"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_margin="10dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/basic_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:minWidth="150dp"
|
||||
android:padding="6dp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/install_option_card"
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="4dp"
|
||||
app:cardCornerRadius="@dimen/card_corner_radius"
|
||||
app:cardElevation="@dimen/card_elevation">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="10dp"
|
||||
android:text="@string/advanced_settings_title"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/keep_force_enc"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_marginStart="50dp"
|
||||
android:text="@string/keep_force_encryption" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/keep_verity"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_marginStart="50dp"
|
||||
android:text="@string/keep_dm_verity" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/install_button"
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:visibility="gone"
|
||||
app:cardCornerRadius="@dimen/card_corner_radius"
|
||||
app:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="5dp"
|
||||
app:srcCompat="@drawable/ic_logo" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/install_text"
|
||||
android:layout_width="180dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:ems="10"
|
||||
android:fontFamily="sans-serif"
|
||||
android:gravity="center"
|
||||
android:text="@string/install"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/uninstall_button"
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:clickable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
app:cardCornerRadius="@dimen/card_corner_radius"
|
||||
app:cardElevation="@dimen/card_elevation"
|
||||
android:focusable="true">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:ems="10"
|
||||
android:fontFamily="sans-serif"
|
||||
android:gravity="center"
|
||||
android:text="@string/uninstall"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
@@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView android:id="@+id/svLog"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/hsvLog"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:ignore="ScrollViewSize">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtLog"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:padding="8dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="10sp" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
</ScrollView>
|
@@ -1,59 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2016 dvdandroid
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout android:id="@+id/container"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="48dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:tint="#757575"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingTop="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"/>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Caption"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@@ -1,78 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="@dimen/card_vertical_margin"
|
||||
android:layout_marginEnd="@dimen/card_horizontal_margin"
|
||||
android:layout_marginStart="@dimen/card_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/card_vertical_margin"
|
||||
style="?attr/cardStyle"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
card_view:cardCornerRadius="@dimen/card_corner_radius"
|
||||
card_view:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/info_layout"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="end" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textIsSelectable="false"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/package_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="false"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/ic_menu_overflow_material"
|
||||
android:checked="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
@@ -1,113 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="@dimen/card_vertical_margin"
|
||||
android:layout_marginEnd="@dimen/card_horizontal_margin"
|
||||
android:layout_marginStart="@dimen/card_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/card_vertical_margin"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
card_view:cardCornerRadius="@dimen/card_corner_radius"
|
||||
card_view:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:padding="@dimen/card_layout_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="@dimen/card_textview_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="0dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textIsSelectable="false"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version_name"
|
||||
android:layout_width="@dimen/card_textview_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@id/title"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:textIsSelectable="false"
|
||||
android:textStyle="bold|italic"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/author"
|
||||
android:layout_width="@dimen/card_textview_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@id/version_name"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:textIsSelectable="false"
|
||||
android:textStyle="bold|italic"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/author"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textIsSelectable="false"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notice"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/description"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/remove_file_created"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@color/red500"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBaseline="@id/title"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end">
|
||||
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="false"
|
||||
android:gravity="center"
|
||||
android:padding="@dimen/checkbox_padding"
|
||||
android:src="@drawable/ic_menu_overflow_material"
|
||||
tools:ignore="ContentDescription"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/delete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:focusable="false"
|
||||
android:gravity="center"
|
||||
android:padding="@dimen/checkbox_padding"
|
||||
android:src="@drawable/ic_delete"
|
||||
android:tint="@color/icon_grey"
|
||||
tools:ignore="ContentDescription"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
@@ -1,172 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="@dimen/card_vertical_margin"
|
||||
android:layout_marginEnd="@dimen/card_horizontal_margin"
|
||||
android:layout_marginStart="@dimen/card_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/card_vertical_margin"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
card_view:cardCornerRadius="@dimen/card_corner_radius"
|
||||
card_view:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/info_layout"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="end" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textIsSelectable="false"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/package_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Switch
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/master_switch"
|
||||
android:layout_weight="0"
|
||||
android:checked="false"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/expand_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_notifications"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:tint="@color/icon_grey"
|
||||
android:layout_marginEnd="10dp" />
|
||||
|
||||
<Switch
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/notification_switch"
|
||||
android:checked="false"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:layout_gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_bug_report"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:tint="@color/icon_grey"
|
||||
android:layout_marginEnd="10dp" />
|
||||
|
||||
<Switch
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/logging_switch"
|
||||
android:checked="false"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/delete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_delete"
|
||||
android:tint="@color/icon_grey"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/more_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_more"
|
||||
android:tint="@color/icon_grey"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
@@ -1,98 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="@dimen/card_vertical_margin"
|
||||
android:layout_marginEnd="@dimen/card_horizontal_margin"
|
||||
android:layout_marginStart="@dimen/card_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/card_vertical_margin"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
card_view:cardCornerRadius="@dimen/card_corner_radius"
|
||||
card_view:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/card_layout_padding">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/info_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:clickable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="0dp"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_info_provided"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:textIsSelectable="false"
|
||||
android:textStyle="bold|italic" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/author"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_info_provided"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:textIsSelectable="false"
|
||||
android:textStyle="bold|italic" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/no_info_provided"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textIsSelectable="false" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/update_time"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@android:color/tertiary_text_dark"
|
||||
android:textIsSelectable="false"
|
||||
android:textStyle="bold|italic" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/download"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="@drawable/ic_file_download_black"
|
||||
android:backgroundTint="@color/icon_grey"
|
||||
android:clickable="true"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:focusable="false"
|
||||
android:gravity="end" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
@@ -1,145 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
style="?attr/cardStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_marginEnd="@dimen/card_horizontal_margin"
|
||||
android:layout_marginStart="@dimen/card_horizontal_margin"
|
||||
android:layout_marginTop="2dp"
|
||||
card_view:cardCornerRadius="@dimen/card_corner_radius"
|
||||
card_view:cardElevation="@dimen/card_elevation">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/info_layout"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textIsSelectable="false"
|
||||
android:layout_weight="2" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/action"
|
||||
android:layout_weight="1"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:gravity="center_horizontal" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/time"
|
||||
android:layout_weight="1"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:gravity="center_horizontal" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/expand_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center_horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:text="@string/pid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/fromPid"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:text="@string/target_uid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/toUid"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_weight="2">
|
||||
|
||||
<TextView
|
||||
android:text="@string/command"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/command"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:gravity="start"
|
||||
android:textSize="12sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
### 6.0.1
|
||||
- Update to use new online module's organizing method
|
||||
- When fingerprint authentication is enabled, toggling root permissions in "Superuser" section now requires fingerprint beforehand
|
||||
- Fix crashes when entering MagiskHide section on some devices
|
||||
- Remove support to Magisk version lower than v15.0
|
||||
- Ask storage permissions before patching stock boot image
|
||||
- Update dark theme CardView color
|
@@ -1,276 +0,0 @@
|
||||
body {
|
||||
font-family: Helvetica, arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
background-color: #424242;
|
||||
color: white;
|
||||
padding: 15px; }
|
||||
|
||||
body > *:first-child {
|
||||
margin-top: 0 !important; }
|
||||
body > *:last-child {
|
||||
margin-bottom: 0 !important; }
|
||||
|
||||
a {
|
||||
color: #4183C4; }
|
||||
a.absent {
|
||||
color: #cc0000; }
|
||||
a.anchor {
|
||||
display: block;
|
||||
padding-left: 30px;
|
||||
margin-left: -30px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0; }
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin: 20px 0 10px;
|
||||
padding: 0;
|
||||
font-weight: bold;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
cursor: text;
|
||||
position: relative; }
|
||||
|
||||
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
|
||||
background: url("../../images/modules/styleguide/para.png") no-repeat 10px center;
|
||||
text-decoration: none; }
|
||||
|
||||
h1 tt, h1 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h2 tt, h2 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h3 tt, h3 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h4 tt, h4 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h5 tt, h5 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h6 tt, h6 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h1 {
|
||||
font-size: 28px; }
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #cccccc; }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
h4 {
|
||||
font-size: 16px; }
|
||||
|
||||
h5 {
|
||||
font-size: 14px; }
|
||||
|
||||
h6 {
|
||||
color: #888888;
|
||||
font-size: 14px; }
|
||||
|
||||
p, blockquote, ul, ol, dl, li, table, pre {
|
||||
margin: 15px 0; }
|
||||
|
||||
hr {
|
||||
background: transparent url("../../images/modules/pulls/dirty-shade.png") repeat-x 0 0;
|
||||
border: 0 none;
|
||||
color: #cccccc;
|
||||
height: 4px;
|
||||
padding: 0; }
|
||||
|
||||
body > h2:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
body > h1:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
body > h1:first-child + h2 {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
|
||||
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
|
||||
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
|
||||
margin-top: 0; }
|
||||
|
||||
li p.first {
|
||||
display: inline-block; }
|
||||
|
||||
ul, ol {
|
||||
padding-left: 30px; }
|
||||
|
||||
ul :first-child, ol :first-child {
|
||||
margin-top: 0; }
|
||||
|
||||
ul :last-child, ol :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
dl {
|
||||
padding: 0; }
|
||||
dl dt {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
padding: 0;
|
||||
margin: 15px 0 5px; }
|
||||
dl dt:first-child {
|
||||
padding: 0; }
|
||||
dl dt > :first-child {
|
||||
margin-top: 0; }
|
||||
dl dt > :last-child {
|
||||
margin-bottom: 0; }
|
||||
dl dd {
|
||||
margin: 0 0 15px;
|
||||
padding: 0 15px; }
|
||||
dl dd > :first-child {
|
||||
margin-top: 0; }
|
||||
dl dd > :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
blockquote {
|
||||
border-left: 4px solid #404040;
|
||||
padding: 0 15px;
|
||||
color: #888888; }
|
||||
blockquote > :first-child {
|
||||
margin-top: 0; }
|
||||
blockquote > :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
table {
|
||||
padding: 0; }
|
||||
table tr {
|
||||
border-top: 1px solid #707070;
|
||||
background-color: #303030;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
table tr:nth-child(2n) {
|
||||
background-color: #505050; }
|
||||
table tr th {
|
||||
font-weight: bold;
|
||||
border: 1px solid #707070;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 6px 13px; }
|
||||
table tr td {
|
||||
border: 1px solid #707070;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 6px 13px; }
|
||||
table tr th :first-child, table tr td :first-child {
|
||||
margin-top: 0; }
|
||||
table tr th :last-child, table tr td :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
img {
|
||||
max-width: 100%; }
|
||||
|
||||
span.frame {
|
||||
display: block;
|
||||
overflow: hidden; }
|
||||
span.frame > span {
|
||||
border: 1px solid #dddddd;
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
padding: 7px;
|
||||
width: auto; }
|
||||
span.frame span img {
|
||||
display: block;
|
||||
float: left; }
|
||||
span.frame span span {
|
||||
clear: both;
|
||||
color: #cccccc;
|
||||
display: block;
|
||||
padding: 5px 0 0; }
|
||||
span.align-center {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both; }
|
||||
span.align-center > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: center; }
|
||||
span.align-center span img {
|
||||
margin: 0 auto;
|
||||
text-align: center; }
|
||||
span.align-right {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both; }
|
||||
span.align-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
text-align: right; }
|
||||
span.align-right span img {
|
||||
margin: 0;
|
||||
text-align: right; }
|
||||
span.float-left {
|
||||
display: block;
|
||||
margin-right: 13px;
|
||||
overflow: hidden;
|
||||
float: left; }
|
||||
span.float-left span {
|
||||
margin: 13px 0 0; }
|
||||
span.float-right {
|
||||
display: block;
|
||||
margin-left: 13px;
|
||||
overflow: hidden;
|
||||
float: right; }
|
||||
span.float-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: right; }
|
||||
|
||||
code, tt {
|
||||
margin: 0 2px;
|
||||
padding: 0 5px;
|
||||
white-space: nowrap;
|
||||
border: 1px solid #707070;
|
||||
background-color: #606060;
|
||||
border-radius: 3px; }
|
||||
|
||||
pre code {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
border: none;
|
||||
background: transparent; }
|
||||
|
||||
.highlight pre {
|
||||
background-color: #3f3f3f;
|
||||
border: 1px solid #707070;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
border-radius: 3px; }
|
||||
|
||||
pre {
|
||||
background-color: #606060;
|
||||
border: 1px solid #707070;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
border-radius: 3px; }
|
||||
pre code, pre tt {
|
||||
background-color: transparent;
|
||||
border: none; }
|
@@ -1,277 +0,0 @@
|
||||
body {
|
||||
font-family: Helvetica, arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
background-color: white;
|
||||
padding: 15px; }
|
||||
|
||||
body > *:first-child {
|
||||
margin-top: 0 !important; }
|
||||
body > *:last-child {
|
||||
margin-bottom: 0 !important; }
|
||||
|
||||
a {
|
||||
color: #4183C4; }
|
||||
a.absent {
|
||||
color: #cc0000; }
|
||||
a.anchor {
|
||||
display: block;
|
||||
padding-left: 30px;
|
||||
margin-left: -30px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0; }
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin: 20px 0 10px;
|
||||
padding: 0;
|
||||
font-weight: bold;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
cursor: text;
|
||||
position: relative; }
|
||||
|
||||
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
|
||||
background: url("../../images/modules/styleguide/para.png") no-repeat 10px center;
|
||||
text-decoration: none; }
|
||||
|
||||
h1 tt, h1 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h2 tt, h2 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h3 tt, h3 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h4 tt, h4 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h5 tt, h5 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h6 tt, h6 code {
|
||||
font-size: inherit; }
|
||||
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
color: black; }
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
color: black; }
|
||||
|
||||
h3 {
|
||||
font-size: 18px; }
|
||||
|
||||
h4 {
|
||||
font-size: 16px; }
|
||||
|
||||
h5 {
|
||||
font-size: 14px; }
|
||||
|
||||
h6 {
|
||||
color: #777777;
|
||||
font-size: 14px; }
|
||||
|
||||
p, blockquote, ul, ol, dl, li, table, pre {
|
||||
margin: 15px 0; }
|
||||
|
||||
hr {
|
||||
background: transparent url("../../images/modules/pulls/dirty-shade.png") repeat-x 0 0;
|
||||
border: 0 none;
|
||||
color: #cccccc;
|
||||
height: 4px;
|
||||
padding: 0; }
|
||||
|
||||
body > h2:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
body > h1:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
body > h1:first-child + h2 {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
|
||||
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
|
||||
margin-top: 0;
|
||||
padding-top: 0; }
|
||||
|
||||
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
|
||||
margin-top: 0; }
|
||||
|
||||
li p.first {
|
||||
display: inline-block; }
|
||||
|
||||
ul, ol {
|
||||
padding-left: 30px; }
|
||||
|
||||
ul :first-child, ol :first-child {
|
||||
margin-top: 0; }
|
||||
|
||||
ul :last-child, ol :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
dl {
|
||||
padding: 0; }
|
||||
dl dt {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
padding: 0;
|
||||
margin: 15px 0 5px; }
|
||||
dl dt:first-child {
|
||||
padding: 0; }
|
||||
dl dt > :first-child {
|
||||
margin-top: 0; }
|
||||
dl dt > :last-child {
|
||||
margin-bottom: 0; }
|
||||
dl dd {
|
||||
margin: 0 0 15px;
|
||||
padding: 0 15px; }
|
||||
dl dd > :first-child {
|
||||
margin-top: 0; }
|
||||
dl dd > :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
blockquote {
|
||||
border-left: 4px solid #dddddd;
|
||||
padding: 0 15px;
|
||||
color: #777777; }
|
||||
blockquote > :first-child {
|
||||
margin-top: 0; }
|
||||
blockquote > :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
table {
|
||||
padding: 0; }
|
||||
table tr {
|
||||
border-top: 1px solid #cccccc;
|
||||
background-color: white;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
table tr:nth-child(2n) {
|
||||
background-color: #f8f8f8; }
|
||||
table tr th {
|
||||
font-weight: bold;
|
||||
border: 1px solid #cccccc;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 6px 13px; }
|
||||
table tr td {
|
||||
border: 1px solid #cccccc;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
padding: 6px 13px; }
|
||||
table tr th :first-child, table tr td :first-child {
|
||||
margin-top: 0; }
|
||||
table tr th :last-child, table tr td :last-child {
|
||||
margin-bottom: 0; }
|
||||
|
||||
img {
|
||||
max-width: 100%; }
|
||||
|
||||
span.frame {
|
||||
display: block;
|
||||
overflow: hidden; }
|
||||
span.frame > span {
|
||||
border: 1px solid #dddddd;
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
padding: 7px;
|
||||
width: auto; }
|
||||
span.frame span img {
|
||||
display: block;
|
||||
float: left; }
|
||||
span.frame span span {
|
||||
clear: both;
|
||||
color: #333333;
|
||||
display: block;
|
||||
padding: 5px 0 0; }
|
||||
span.align-center {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both; }
|
||||
span.align-center > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: center; }
|
||||
span.align-center span img {
|
||||
margin: 0 auto;
|
||||
text-align: center; }
|
||||
span.align-right {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both; }
|
||||
span.align-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px 0 0;
|
||||
text-align: right; }
|
||||
span.align-right span img {
|
||||
margin: 0;
|
||||
text-align: right; }
|
||||
span.float-left {
|
||||
display: block;
|
||||
margin-right: 13px;
|
||||
overflow: hidden;
|
||||
float: left; }
|
||||
span.float-left span {
|
||||
margin: 13px 0 0; }
|
||||
span.float-right {
|
||||
display: block;
|
||||
margin-left: 13px;
|
||||
overflow: hidden;
|
||||
float: right; }
|
||||
span.float-right > span {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin: 13px auto 0;
|
||||
text-align: right; }
|
||||
|
||||
code, tt {
|
||||
margin: 0 2px;
|
||||
padding: 0 5px;
|
||||
white-space: nowrap;
|
||||
border: 1px solid #eaeaea;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 3px; }
|
||||
|
||||
pre code {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
border: none;
|
||||
background: transparent; }
|
||||
|
||||
.highlight pre {
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #cccccc;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
border-radius: 3px; }
|
||||
|
||||
pre {
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #cccccc;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
overflow: auto;
|
||||
padding: 6px 10px;
|
||||
border-radius: 3px; }
|
||||
pre code, pre tt {
|
||||
background-color: transparent;
|
||||
border: none; }
|
@@ -1,111 +0,0 @@
|
||||
db_sepatch() {
|
||||
magiskpolicy --live 'create magisk_file' 'attradd magisk_file mlstrustedobject' \
|
||||
'allow * magisk_file file *' 'allow * magisk_file dir *' \
|
||||
'allow magisk_file * filesystem associate'
|
||||
}
|
||||
|
||||
db_clean() {
|
||||
local USERID=$1
|
||||
local DIR="/sbin/.core/db-${USERID}"
|
||||
umount -l /data/user*/*/*/databases/su.db $DIR $DIR/*
|
||||
rm -rf $DIR
|
||||
[ "$USERID" = "*" ] && rm -fv /data/adb/magisk.db*
|
||||
}
|
||||
|
||||
db_init() {
|
||||
# Temporary let the folder rw by anyone
|
||||
chcon u:object_r:magisk_file:s0 /data/adb
|
||||
chmod 777 /data/adb
|
||||
}
|
||||
|
||||
db_restore() {
|
||||
chmod 700 /data/adb
|
||||
magisk --restorecon
|
||||
}
|
||||
|
||||
db_setup() {
|
||||
local USER=$1
|
||||
local USERID=$(($USER / 100000))
|
||||
local DIR=/sbin/.core/db-${USERID}
|
||||
mkdir -p $DIR
|
||||
touch $DIR/magisk.db
|
||||
mount -o bind /data/adb/magisk.db $DIR/magisk.db
|
||||
rm -f /data/adb/magisk.db-*
|
||||
chcon u:object_r:magisk_file:s0 $DIR $DIR/*
|
||||
chmod 700 $DIR
|
||||
chown $USER.$USER $DIR
|
||||
chmod 666 $DIR/*
|
||||
}
|
||||
|
||||
env_check() {
|
||||
for file in busybox magisk magiskboot magiskinit util_functions.sh boot_patch.sh; do
|
||||
[ -f /data/adb/magisk/$file ] || return 1
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
fix_env() {
|
||||
cd /data/adb/magisk
|
||||
sh update-binary extract
|
||||
rm -f update-binary magisk.apk
|
||||
cd /
|
||||
rm -rf /sbin/.core/busybox/*
|
||||
/sbin/.core/mirror/bin/busybox --install -s /sbin/.core/busybox
|
||||
}
|
||||
|
||||
direct_install() {
|
||||
rm -rf /data/adb/magisk/* 2>/dev/null
|
||||
mkdir -p /data/adb/magisk 2>/dev/null
|
||||
chmod 700 /data/adb
|
||||
cp -rf $1/* /data/adb/magisk
|
||||
rm -rf /data/adb/magisk/new-boot.img
|
||||
echo "- Flashing new boot image"
|
||||
flash_image $1/new-boot.img $2
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "! Insufficient partition size"
|
||||
return 1
|
||||
fi
|
||||
rm -rf $1
|
||||
return 0
|
||||
}
|
||||
|
||||
mm_patch_dtbo() {
|
||||
if $KEEPVERITY; then
|
||||
return 1
|
||||
else
|
||||
find_dtbo_image
|
||||
patch_dtbo_image
|
||||
fi
|
||||
}
|
||||
|
||||
restore_imgs() {
|
||||
local SHA1=`cat /.backup/.sha1`
|
||||
[ -z $SHA1 ] && local SHA1=`grep_prop #STOCKSHA1`
|
||||
[ -z $SHA1 ] && return 1
|
||||
local STOCKBOOT=/data/stock_boot_${SHA1}.img.gz
|
||||
local STOCKDTBO=/data/stock_dtbo.img.gz
|
||||
[ -f $STOCKBOOT ] || return 1
|
||||
|
||||
find_boot_image
|
||||
find_dtbo_image
|
||||
|
||||
if [ -f $STOCKDTBO -a -b "$DTBOIMAGE" ]; then
|
||||
flash_image $STOCKDTBO $DTBOIMAGE
|
||||
fi
|
||||
if [ -f $STOCKBOOT -a -b "$BOOTIMAGE" ]; then
|
||||
flash_image $STOCKBOOT $BOOTIMAGE
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
post_ota() {
|
||||
cd $1
|
||||
chmod 755 bootctl
|
||||
./bootctl hal-info || return
|
||||
[ `./bootctl get-current-slot` -eq 0 ] && SLOT_NUM=1 || SLOT_NUM=0
|
||||
./bootctl set-active-boot-slot $SLOT_NUM
|
||||
echo '${0%/*}/../bootctl mark-boot-successful;rm -f ${0%/*}/../bootctl $0' > post-fs-data.d/post_ota.sh
|
||||
chmod 755 post-fs-data.d/post_ota.sh
|
||||
cd /
|
||||
}
|
@@ -1,146 +0,0 @@
|
||||
<resources>
|
||||
<!--Universal-->
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="modules">الإضافات</string>
|
||||
<string name="downloads">التنزيلات</string>
|
||||
<string name="superuser">Superuser</string>
|
||||
<string name="log">السجل</string>
|
||||
<string name="settings">الإعدادات</string>
|
||||
<string name="install">التثبيت</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version_error">Magisk غير مثبت</string>
|
||||
|
||||
<string name="checking_for_updates">البحث عن تحديثات…</string>
|
||||
<string name="magisk_update_available">Magisk v%1$s متاح!</string>
|
||||
<string name="safetyNet_check_text">انقر لبدء فحص SafetyNet</string>
|
||||
<string name="checking_safetyNet_status">التحقق من حالة SafetyNet…</string>
|
||||
<string name="safetyNet_check_success">نجح فحص SafetyNet</string>
|
||||
<string name="safetyNet_res_invalid">الاستجابة غير صالحه</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="advanced_settings_title">إعدادات متقدمة</string>
|
||||
<string name="keep_force_encryption">الحفاظ علي قوه التشفير</string>
|
||||
<string name="keep_dm_verity">إبقاء AVB 2.0/dm-verity</string>
|
||||
<string name="current_magisk_title">نسخة Magisk المثبته: %1$s</string>
|
||||
<string name="install_magisk_title">آخر نسخة Magisk: %1$s</string>
|
||||
<string name="uninstall">إلغاء التثبيت</string>
|
||||
<string name="uninstall_magisk_title">إلغاء تثبيت Magisk</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(لم يتم توفير أي معلومات)</string>
|
||||
<string name="no_modules_found">لم يعثر على الإضافات</string>
|
||||
<string name="update_file_created">سيتم تحديث الإضافة في إعادة التشغيل التالي</string>
|
||||
<string name="remove_file_created">سيتم حذف الإضافة في إعادة التشغيل التالي</string>
|
||||
<string name="remove_file_deleted">لن يتم حذف الإضافة في إعادة التشغيل التالي</string>
|
||||
<string name="disable_file_created">سيتم تعطيل الإضافة في إعادة التشغيل التالي</string>
|
||||
<string name="disable_file_removed">سيتم تمكين الإضافة في إعادة التشغيل التالي</string>
|
||||
<string name="author">انشئ بواسطة %1$s</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">يتوفر تحديث</string>
|
||||
<string name="installed">مثبت</string>
|
||||
<string name="not_installed">غير مثبت</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuReload">إعادة تحميل</string>
|
||||
<string name="menuClearLog">حذف السجل الآن</string>
|
||||
<string name="logs_cleared">تم حذف السجل بنجاح</string>
|
||||
<string name="log_is_empty">السجل فارغ</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">حول</string>
|
||||
<string name="app_changelog">تغييرات التطبيق</string>
|
||||
<string name="translators">xx6600xx ,silent_6600</string>
|
||||
<string name="app_version">إصدار التطبيق</string>
|
||||
<string name="app_source_code">الشفرة المصدرية</string>
|
||||
<string name="donation">التبرع</string>
|
||||
<string name="app_translators">مترجم التطبيق</string>
|
||||
<string name="support_thread">منتدى الدعم</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="close">إغلاق</string>
|
||||
<string name="repo_install_title">تثبيت %1$s</string>
|
||||
<string name="repo_install_msg">هل تريد تثبيت %1$s ?</string>
|
||||
<string name="download">التنزيل</string>
|
||||
<string name="reboot">إعادة التشغيل</string>
|
||||
<string name="zip_process_msg">معالجة الملف المضغوط …</string>
|
||||
<string name="magisk_update_title">تحديث Magisk جديد متوفر!</string>
|
||||
<string name="settings_reboot_toast">إعادة التشغيل لتطبيق الإعدادات</string>
|
||||
<string name="release_notes">ملاحظات الإصدار</string>
|
||||
<string name="repo_cache_cleared">تم مسح الذاكرة المؤقته للمستودع</string>
|
||||
<string name="process_error">خطأ في العملية</string>
|
||||
<string name="internal_storage">يتم تخزين الملف المضغوط في:\n[التخزين الداخلي]%1$s</string>
|
||||
<string name="zip_process_title">معالجة</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">عام</string>
|
||||
<string name="settings_dark_theme_title">السمة الغامقة</string>
|
||||
<string name="settings_dark_theme_summary">تفعيل السمة الغامقة</string>
|
||||
<string name="settings_clear_cache_title">حذف الذاكرة المؤقتة للمستودع</string>
|
||||
<string name="settings_clear_cache_summary">حذف المعلومات المخزنة مؤقتا للمستودع على الانترنت، يجبر التطبيق لتحديث عبر الانترنت</string>
|
||||
|
||||
<string name="settings_core_only_title">Magisk الوضع الأساسي فقط</string>
|
||||
<string name="settings_core_only_summary">تمكين الميزات الأساسية فقط، لن يتم تحميل جميع الإضافات. MagiskSU، MagiskHide، systemless hosts، و لا يزال ممكنا</string>
|
||||
<string name="settings_magiskhide_summary">إخفاء Magisk من مختلف الاكتشافات</string>
|
||||
<string name="settings_hosts_title">تمكين المضيفين(الهوست) لـ systemless</string>
|
||||
<string name="settings_hosts_summary">Systemless يدعم تطبيقات حجب الإعلانات</string>
|
||||
|
||||
<string name="settings_su_app_adb">التطبيقات و ADB</string>
|
||||
<string name="settings_su_app">التطبيقات فقط</string>
|
||||
<string name="settings_su_adb">ADB فقط</string>
|
||||
<string name="settings_su_disable">معطل</string>
|
||||
<string name="settings_su_request_10">10 ثواني</string>
|
||||
<string name="settings_su_request_20">20 ثانية</string>
|
||||
<string name="settings_su_request_30">30 ثانية</string>
|
||||
<string name="settings_su_request_60">60 ثانية</string>
|
||||
<string name="superuser_access">Superuser صلاحيات</string>
|
||||
<string name="auto_response">استجابة تلقائية</string>
|
||||
<string name="request_timeout">مهلة الطلب</string>
|
||||
<string name="superuser_notification">Superuser إشعارات</string>
|
||||
<string name="request_timeout_summary">%1$s ثانية</string>
|
||||
|
||||
<string name="multiuser_mode">وضع تعدد المستخدمين</string>
|
||||
<string name="settings_owner_only">مالك الجهاز فقط</string>
|
||||
<string name="settings_owner_manage">إدارة مالك الجهاز</string>
|
||||
<string name="settings_user_independent">مستخدم مستقل</string>
|
||||
<string name="owner_only_summary">المالك فقط لديه صلاحيات الروت</string>
|
||||
<string name="owner_manage_summary">يمكن للمالك فقط إدارة صلاحيات الروت وتلقي مطالبات الطلب</string>
|
||||
<string name="user_indepenent_summary">كل مستخدم لديه قواعد روت منفصلة خاصة به</string>
|
||||
<string name="multiuser_hint_owner_request">تم إرسال طلب إلى مالك الجهاز. يرجى التبديل إلى المالك ومنح الإذن</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Superuser طلبات</string>
|
||||
<string name="deny_with_str">رفض%1$s</string>
|
||||
<string name="deny">رفض</string>
|
||||
<string name="prompt">طلب</string>
|
||||
<string name="grant">سماح</string>
|
||||
<string name="su_warning">منح حق الوصول الكامل إلى جهازك.\nرفض إذا كنت غير متأكد!</string>
|
||||
<string name="forever">للابد</string>
|
||||
<string name="once">مره</string>
|
||||
<string name="tenmin">10 دقائق</string>
|
||||
<string name="twentymin">20 دقائق</string>
|
||||
<string name="thirtymin">30 دقائق</string>
|
||||
<string name="sixtymin">60 دقائق</string>
|
||||
<string name="su_allow_toast">%1$s يتم منح صلاحيات Superuser</string>
|
||||
<string name="su_deny_toast">%1$s يتم رفض صلاحيات Superuser</string>
|
||||
<string name="no_apps_found">لا توجد تطبيقات</string>
|
||||
<string name="su_snack_grant">Superuser الصلاحيات لـ %1$s تم منحها</string>
|
||||
<string name="su_snack_deny">Superuser الصلاحيات لـ %1$s تم رفضها</string>
|
||||
<string name="su_snack_notif_on">الإشعارات لـ %1$s تم تفعيلها</string>
|
||||
<string name="su_snack_notif_off">الإشعارات لـ %1$s تم تعطيلها</string>
|
||||
<string name="su_snack_log_on">السجلات لـ %1$s تم تفعيلها</string>
|
||||
<string name="su_snack_log_off">السجلات لـ %1$s تم تعطيلها</string>
|
||||
<string name="su_snack_revoke">%1$s الصلاحيات سحبت</string>
|
||||
<string name="su_revoke_title">سحب؟</string>
|
||||
<string name="su_revoke_msg">تأكيد لسحب صلاحيات %1$s ?</string>
|
||||
<string name="toast">نخب</string>
|
||||
<string name="none">بدون</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID:\u0020</string>
|
||||
<string name="target_uid">الهدف UID:\u0020</string>
|
||||
<string name="command">الأمر:\u0020</string>
|
||||
|
||||
</resources>
|
@@ -1,223 +0,0 @@
|
||||
<resources>
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="modules">Модули</string>
|
||||
<string name="downloads">Изтегляния</string>
|
||||
<string name="superuser">Superuser</string>
|
||||
<string name="log">Дневник</string>
|
||||
<string name="settings">Настройки</string>
|
||||
<string name="install">Инсталиране</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version_error">Magisk не е инсталиран</string>
|
||||
<string name="checking_for_updates">Проверяваме за актуализации…</string>
|
||||
<string name="magisk_update_available">Magisk версия %1$s е налице!</string>
|
||||
<string name="invalid_update_channel">Невалиден канал за актуализации</string>
|
||||
<string name="safetyNet_check_text">Докоснете за стартиране на SafetyNet проверката</string>
|
||||
<string name="checking_safetyNet_status">Проверяване статуса на SafetyNet…</string>
|
||||
<string name="safetyNet_check_success">SafetyNet проверката е успешна</string>
|
||||
<string name="safetyNet_api_error">Грешка в SafetyNet ППИ</string>
|
||||
<string name="safetyNet_res_invalid">Невалиден отговор</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="advanced_settings_title">Допълнителни настройки</string>
|
||||
<string name="keep_force_encryption">Запазване на наложеното криптиране</string>
|
||||
<string name="keep_dm_verity">Запазване на AVB 2.0/dm-verity</string>
|
||||
<string name="current_magisk_title">Инсталирана версия: %1$s</string>
|
||||
<string name="install_magisk_title">Най-нова версия: %1$s</string>
|
||||
<string name="uninstall">Деинсталиране</string>
|
||||
<string name="uninstall_magisk_title">Деинсталиране на Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Всички модули ще бъдат изключени/премахнати. Руут достъпът ще бъде премахнат и е възможно криптиране на данните Ви</string>
|
||||
<string name="update">Актуализация %1$s</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Не е представена информация)</string>
|
||||
<string name="no_modules_found">Няма намерени модули</string>
|
||||
<string name="update_file_created">Модулът ще бъде обновен при следващото рестартиране</string>
|
||||
<string name="remove_file_created">Модулът ще бъде премахнат при следващото рестартиране</string>
|
||||
<string name="remove_file_deleted">Модулът няма да бъде премахнат при следващото рестартиране</string>
|
||||
<string name="disable_file_created">Модулът ще бъде изключен при следващото рестартиране</string>
|
||||
<string name="disable_file_removed">Модулът ще бъде активиран при следващото рестартиране</string>
|
||||
<string name="author">Създаден от %1$s</string>
|
||||
<string name="reboot_recovery">Рестартиране в режима за възстановяване</string>
|
||||
<string name="reboot_bootloader">Рестартиране в буутлоудъра</string>
|
||||
<string name="reboot_download">Рестартиране в даунлоуд режима</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Налице е актуализация</string>
|
||||
<string name="installed">Инсталиран</string>
|
||||
<string name="not_installed">Не е инсталиран</string>
|
||||
<string name="updated_on">Актуализиран на: %1$s</string>
|
||||
<string name="sorting_order">Сортиране</string>
|
||||
<string name="sort_by_name">Сортиране по наименование</string>
|
||||
<string name="sort_by_update">Сортиране по последно обновяване</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveLog">Запазване на доклад</string>
|
||||
<string name="menuReload">Презареждане</string>
|
||||
<string name="menuClearLog">Изчистване на дневника</string>
|
||||
<string name="logs_cleared">Успешно изчистване на дневника</string>
|
||||
<string name="log_is_empty">Дневникът е празен</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">Относно</string>
|
||||
<string name="app_changelog">Списък с промени</string>
|
||||
<string name="translators" />
|
||||
<string name="app_version">Версия</string>
|
||||
<string name="app_source_code">Изходен код</string>
|
||||
<string name="donation">Дарение</string>
|
||||
<string name="app_translators">Преводачи</string>
|
||||
<string name="support_thread">Страница за поддръжка</string>
|
||||
<string name="follow_twitter">Последвайте ме в Twitter</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="close">Затваряне</string>
|
||||
<string name="repo_install_title">Инсталиране на %1$s</string>
|
||||
<string name="repo_install_msg">Желаете ли да инсталирате %1$s сега?</string>
|
||||
<string name="download">Изтегляне</string>
|
||||
<string name="reboot">Рестартиране</string>
|
||||
<string name="magisk_update_title">Налице е нова версия на Magisk!</string>
|
||||
<string name="settings_reboot_toast">Трябва да рестартирате за прилагане на настройките</string>
|
||||
<string name="release_notes">Бележки</string>
|
||||
<string name="repo_cache_cleared">Кешът на хранилището е изчистен</string>
|
||||
<string name="process_error">Грешка при процеса</string>
|
||||
<string name="internal_storage">Архивът е записан във:\n[Вътрешната памет]%1$s</string>
|
||||
<string name="zip_download_title">Изтегляне</string>
|
||||
<string name="zip_download_msg">Изтегляне на архив (%1$d%%)…</string>
|
||||
<string name="zip_process_title">Обработване</string>
|
||||
<string name="zip_process_msg">Обработване на архива…</string>
|
||||
<string name="manager_update_title">Налице е нова версия на Magisk Manager!</string>
|
||||
<string name="manager_download_install">Докоснете за изтегляне и инсталиране</string>
|
||||
<string name="dtbo_patched_title">DTBO беше модифициран!</string>
|
||||
<string name="dtbo_patched_reboot">Magisk Manager модифицира dtbo.img, моля да рестартирате</string>
|
||||
<string name="magisk_updates">Актуализации на Magisk</string>
|
||||
<string name="flashing">Инсталиране</string>
|
||||
<string name="hide_manager_toast">Скриване на Magisk Manager…</string>
|
||||
<string name="hide_manager_toast2">Може да отнеме време…</string>
|
||||
<string name="hide_manager_fail_toast">Скриването на Magisk Manager е неуспешно…</string>
|
||||
<string name="open_link_failed_toast">Не бе намерено приложение за отваряне на линка…</string>
|
||||
<string name="download_zip_only">Изтегляне само на архив</string>
|
||||
<string name="patch_boot_file">Модифициране на Boot образа</string>
|
||||
<string name="direct_install">Директно инсталиране (Препоръчва се)</string>
|
||||
<string name="install_inactive_slot">Инсталиране на неактивен слот (След OTA)</string>
|
||||
<string name="warning">Внимание</string>
|
||||
<string name="install_inactive_slot_msg">Вашето устройство НАЛОЖИТЕЛНО ще стартира текущия неактивен слот при следващото рестартиране!\nИзползвайте тази опция само след приключване на OTA актуализация.\nПродължаване?</string>
|
||||
. <string name="select_method">Избор на метод</string>
|
||||
<string name="no_boot_file_patch_support">Избраната версия на Magisk не поддържа модифициране на Boot образи</string>
|
||||
<string name="boot_file_patch_msg">Изберете стоков Boot образ с формат .img или .img.tar</string>
|
||||
<string name="complete_uninstall">Пълно деинсталиране</string>
|
||||
<string name="restore_img">Възстановяване на образи</string>
|
||||
<string name="restore_img_msg">Възстановяване…</string>
|
||||
<string name="restore_done">Възстановяването е успешно!</string>
|
||||
<string name="restore_fail">Не е налице архив на стоковия образ!</string>
|
||||
<string name="proprietary_title">Изтегляне на патентования код</string>
|
||||
<string name="proprietary_notice">Magisk Manager е FOSS и затова не включва частния код за SafetyNet ППИ на Google.\n\nПозволявате ли на Magisk Manager да изтегли добавката (включва GoogleApiClient) за SafetyNet проверки?</string>
|
||||
<string name="su_db_corrupt">Базата данни за SU е повредена, ще създадем нов db файл</string>
|
||||
<string name="setup_done">Първоначалната настройка е готова</string>
|
||||
<string name="setup_fail">Първоначалната настройка е неуспешна</string>
|
||||
<string name="env_fix_title">Изисква допълнително настройване</string>
|
||||
<string name="env_fix_msg">Вашето устройство се нуждае от допълнителни настройки за Magisk, за да работи перфектно. Ще бъде изтеглен архивът за настройка на Magisk. Желаете ли да продължите?</string>
|
||||
<string name="setup_title">Допълнителни настройване</string>
|
||||
<string name="setup_msg">Настройването на средата е в ход…</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Общи</string>
|
||||
<string name="settings_dark_theme_title">Тъмна тема</string>
|
||||
<string name="settings_dark_theme_summary">Включване на тъмната тема</string>
|
||||
<string name="settings_clear_cache_title">Изчистване кеша на хранилището</string>
|
||||
<string name="settings_clear_cache_summary"> Изчистване на кешираната информация на онлайн хранилището за принудително обновяване</string>
|
||||
<string name="settings_hide_manager_title">Скриване на Magisk Manager</string>
|
||||
<string name="settings_hide_manager_summary">Смяна пакетното наименование на Magisk Manager със случайно наименование</string>
|
||||
<string name="settings_restore_manager_title">Възстановяване на Magisk Manager</string>
|
||||
<string name="settings_restore_manager_summary">Възстановяване на оригиналното пакетно наименование на Magisk Manager</string>
|
||||
<string name="language">Език</string>
|
||||
<string name="system_default">(Системен)</string>
|
||||
<string name="settings_update">Настройки за актуализиране</string>
|
||||
<string name="settings_check_update_title">Проверка за актуализации</string>
|
||||
<string name="settings_check_update_summary">Периодично проверяване за актуализации във фонов режим</string>
|
||||
<string name="settings_update_channel_title">Канал за актуализации</string>
|
||||
<string name="settings_update_stable">Стабилен</string>
|
||||
<string name="settings_update_beta">Бета</string>
|
||||
<string name="settings_update_custom">Потребителски</string>
|
||||
<string name="settings_update_custom_msg">Въведете потребителски URL</string>
|
||||
<string name="settings_boot_format_title">Изходен формат за модифициран Boot образ</string>
|
||||
<string name="settings_boot_format_summary">Избор на изходен формат за модифициран Boot образ.\nИзберете .img, за инсталиране чрез fastboot/download режим; изберете .img.tar за инсталиране чрез ODIN.</string>
|
||||
<string name="settings_core_only_title">Режим Magisk Core Only</string>
|
||||
<string name="settings_core_only_summary">Работят само основни функции, като MagiskSU, MagiskHide и несистемни хостове, без модули.</string>
|
||||
<string name="settings_magiskhide_summary">Скриване на Magisk от различни детектори</string>
|
||||
<string name="settings_hosts_title">Несистемни хостове</string>
|
||||
<string name="settings_hosts_summary">Поддръжка на несистемни хостове за използване на приложения, блокиращи реклами</string>
|
||||
|
||||
<string name="settings_su_app_adb">Приложения и ADB</string>
|
||||
<string name="settings_su_app">Само приложения</string>
|
||||
<string name="settings_su_adb">Само ADB</string>
|
||||
<string name="settings_su_disable">Изключен</string>
|
||||
<string name="settings_su_request_10">10 секунди</string>
|
||||
<string name="settings_su_request_20">20 секунди</string>
|
||||
<string name="settings_su_request_30">30 секунди</string>
|
||||
<string name="settings_su_request_60">60 секунди</string>
|
||||
<string name="superuser_access">Superuser достъп</string>
|
||||
<string name="auto_response">Автоматичен отговор</string>
|
||||
<string name="request_timeout">Време за запитване</string>
|
||||
<string name="superuser_notification">Superuser известие</string>
|
||||
<string name="request_timeout_summary">%1$s секунди</string>
|
||||
<string name="settings_su_reauth_title">Повторно запитване след ъпгрейд</string>
|
||||
<string name="settings_su_reauth_summary">Повторно запитване за Superuser достъп след ъпгрейд на приложение</string>
|
||||
<string name="settings_su_fingerprint_title"> Superuser права само с пръстов отпечатък</string>
|
||||
<string name="settings_su_fingerprint_summary">Използване на сензора за пръстови отпечатъци за разрешаване на Superuser досъп</string>
|
||||
<string name="auth_fingerprint">Удостоверете с пръстов отпечатък</string>
|
||||
|
||||
<string name="multiuser_mode">Потребителски достъп</string>
|
||||
<string name="settings_owner_only">Само собственик</string>
|
||||
<string name="settings_owner_manage">Управление от страна на собственика</string>
|
||||
<string name="settings_user_independent">Независими потребители</string>
|
||||
<string name="owner_only_summary">Само собственикът има руут достъп</string>
|
||||
<string name="owner_manage_summary">Само собственикът може да управлява руут достъпа и да получава запитвания за достъп</string>
|
||||
<string name="user_indepenent_summary">Всеки потребител има собствени правила за руут достъп</string>
|
||||
<string name="multiuser_hint_owner_request">Направено е запитване до собственика на устройството. Моля да преминете в режим на собственик и да дадете разрешение</string>
|
||||
|
||||
<string name="mount_namespace_mode">Монтиране по именни пространства</string>
|
||||
<string name="settings_ns_global">Глобално</string>
|
||||
<string name="settings_ns_requester">Наследено</string>
|
||||
<string name="settings_ns_isolate">Изолирано</string>
|
||||
<string name="global_summary">Всички сесии с руут достъп използват глобалното именно пространство</string>
|
||||
<string name="requester_summary">Всички сесии с руут достъп наследяват именното пространство на запитващото приложение</string>
|
||||
<string name="isolate_summary">Всички сесии с руут достъп имат собствени именни пространства</string>
|
||||
<string name="android_o_not_support">Не поддържа Android 8.0+</string>
|
||||
<string name="disable_fingerprint">Не са добавени пръстови отпечатъци или устройството не поддържа тази функция</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Запитване за Superuser достъп</string>
|
||||
<string name="deny_with_str">Отказ%1$s</string>
|
||||
<string name="deny">Отказ</string>
|
||||
<string name="prompt">Запитване</string>
|
||||
<string name="grant">Разрешаване</string>
|
||||
<string name="su_warning">Дава пълен достъп до устройството Ви.\Откажете, ако не Сте сигурен/на!</string>
|
||||
<string name="forever">Завинаги</string>
|
||||
<string name="once">Веднъж</string>
|
||||
<string name="tenmin">10 мин</string>
|
||||
<string name="twentymin">20 мин</string>
|
||||
<string name="thirtymin">30 мин</string>
|
||||
<string name="sixtymin">60 мин</string>
|
||||
<string name="su_allow_toast">На %1$s бе разрешен Superuser достъп</string>
|
||||
<string name="su_deny_toast">На %1$s бе отказан Superuser достъп</string>
|
||||
<string name="no_apps_found">Няма намерени приложения</string>
|
||||
<string name="su_snack_grant">На %1$s е предоставен Superuser достъп</string>
|
||||
<string name="su_snack_deny">На %1$s е отказан Superuser достъп</string>
|
||||
<string name="su_snack_notif_on">Извесията за %1$s са включени</string>
|
||||
<string name="su_snack_notif_off">Извесията за %1$s са изключени</string>
|
||||
<string name="su_snack_log_on">Записването в дневника за %1$s е включено</string>
|
||||
<string name="su_snack_log_off">Записването в дневника за %1$s е изключено</string>
|
||||
<string name="su_snack_revoke">Настройките за достъп на %1$s са анулирани</string>
|
||||
<string name="su_revoke_title">Анулиране?</string>
|
||||
<string name="su_revoke_msg">Потвърждавате ли анулирането на настройките за достъп на %1$s?</string>
|
||||
<string name="toast">Toast</string>
|
||||
<string name="none">Без</string>
|
||||
<string name="auth_fail">Неуспешна заверка</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID:\u0020</string>
|
||||
<string name="target_uid">Целеви UID:\u0020</string>
|
||||
<string name="command">Команда:\u0020</string>
|
||||
|
||||
</resources>
|
@@ -1,135 +0,0 @@
|
||||
<resources>
|
||||
<!--Universal-->
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="modules">Moduly</string>
|
||||
<string name="downloads">Stahování</string>
|
||||
<string name="superuser">Superuser</string>
|
||||
<string name="log">Log</string>
|
||||
<string name="settings">Nastavení</string>
|
||||
<string name="install">Instalovat</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version_error">Magisk není nainstalován</string>
|
||||
|
||||
<string name="checking_for_updates">Kontrola aktualizací…</string>
|
||||
<string name="magisk_update_available">Magisk v%1$s je dostupný!</string>
|
||||
<string name="safetyNet_check_text">Kliknutím zahájíte SafetyNet kontrolu</string>
|
||||
<string name="checking_safetyNet_status">Kontrola stavu SafetyNet…</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="advanced_settings_title">Pokročilá Nastavení</string>
|
||||
<string name="keep_force_encryption">Udržet "force encryption"</string>
|
||||
<string name="keep_dm_verity">Udržet AVB 2.0/dm-verity</string>
|
||||
<string name="current_magisk_title">Nainstalovaná verze: %1$s</string>
|
||||
<string name="install_magisk_title">Poslední verze: %1$s</string>
|
||||
<string name="uninstall">Odinstalovat</string>
|
||||
<string name="uninstall_magisk_title">Odinstalovat Magisk</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Žádné info)</string>
|
||||
<string name="no_modules_found">Žádný modul nenalezen</string>
|
||||
<string name="update_file_created">Modul bude aktualizován během příštího restartu</string>
|
||||
<string name="remove_file_created">Modul bude smazán během příštího restartu</string>
|
||||
<string name="remove_file_deleted">Modul nebude smazán během příštího restartu</string>
|
||||
<string name="disable_file_created">Modul bude zakázán během příštího restartu</string>
|
||||
<string name="disable_file_removed">Modul bude povolen během příštího restartu</string>
|
||||
<string name="author">Vytvořeno %1$s</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Dostupná Aktualizace</string>
|
||||
<string name="installed">Nainstalováno</string>
|
||||
<string name="not_installed">Nenainstalováno</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveLog">Uložit log</string>
|
||||
<string name="menuReload">Aktualizovat</string>
|
||||
<string name="menuClearLog">Smazat Log</string>
|
||||
<string name="logs_cleared">Log byl smazán</string>
|
||||
<string name="log_is_empty">Log je prázdný</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">O aplikaci</string>
|
||||
<string name="app_changelog">Seznam změn</string>
|
||||
<string name="translators" />
|
||||
<string name="app_version">Verze aplikace</string>
|
||||
<string name="app_source_code">Zdrojový kód</string>
|
||||
<string name="donation">Příspěvek</string>
|
||||
<string name="app_translators">Překladatelé aplikace</string>
|
||||
<string name="support_thread">Vlákno podpory na fóru</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
|
||||
<string name="close">Zavřít</string>
|
||||
<string name="repo_install_title">Instalovat %1$s</string>
|
||||
<string name="repo_install_msg">Chcete nainstalovat %1$s ?</string>
|
||||
<string name="download">Stáhnout</string>
|
||||
<string name="reboot">Restart</string>
|
||||
<string name="zip_process_msg">Zpracování zip souboru …</string>
|
||||
<string name="magisk_update_title">K dispozici je aktualizace Magisk!</string>
|
||||
<string name="settings_reboot_toast">Restartovat pro použití nastavení</string>
|
||||
<string name="release_notes">Poznámky k vydání</string>
|
||||
<string name="repo_cache_cleared">Mezipaměť smazána</string>
|
||||
<string name="process_error">Chyba při Zpracování</string>
|
||||
<string name="internal_storage">Zip je uchován v:\n[Interním Úložišti]%1$s</string>
|
||||
<string name="zip_process_title">Zpracování</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Obecné</string>
|
||||
<string name="settings_dark_theme_title">Tmavý Vzhled</string>
|
||||
<string name="settings_dark_theme_summary">Povolit tmavý vzhled</string>
|
||||
<string name="settings_clear_cache_title">Smazat Uchovanou Mezipaměť</string>
|
||||
<string name="settings_clear_cache_summary">Smaže informace online použití v Mezipaměti, donutí aplikaci obnovit informace online</string>
|
||||
|
||||
<string name="settings_magiskhide_summary">Skryje root (MagiskSU) před různými aplikacemi</string>
|
||||
<string name="settings_hosts_title">Nesystémová "hosts" data</string>
|
||||
<string name="settings_hosts_summary">Podpora nesystémových dat "hosts" pro Adblock aplikace</string>
|
||||
|
||||
<string name="settings_su_app_adb">Aplikace i ADB</string>
|
||||
<string name="settings_su_app">Pouze aplikace</string>
|
||||
<string name="settings_su_adb">Pouze ADB</string>
|
||||
<string name="settings_su_disable">Zakázáno</string>
|
||||
<string name="settings_su_request_10">10 sekund</string>
|
||||
<string name="settings_su_request_20">20 sekund</string>
|
||||
<string name="settings_su_request_30">30 sekund</string>
|
||||
<string name="settings_su_request_60">60 sekund</string>
|
||||
<string name="superuser_access">Přístup Superuser</string>
|
||||
<string name="auto_response">Automatická Reakce</string>
|
||||
<string name="request_timeout">Časový limit Požadavku</string>
|
||||
<string name="superuser_notification">Oznámení Superuser</string>
|
||||
<string name="request_timeout_summary">%1$s sekund</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Požadavek Superuser</string>
|
||||
<string name="deny_with_str">Zamítnout%1$s</string>
|
||||
<string name="deny">Zamítnout</string>
|
||||
<string name="prompt">Dotaz</string>
|
||||
<string name="grant">Povolit</string>
|
||||
<string name="su_warning">Povolí plný přístup k vašemu zařízení.\nZamítněte pokud si nejste jisti!</string>
|
||||
<string name="forever">Navždy</string>
|
||||
<string name="once">Jednou</string>
|
||||
<string name="tenmin">10 min</string>
|
||||
<string name="twentymin">20 min</string>
|
||||
<string name="thirtymin">30 min</string>
|
||||
<string name="sixtymin">60 min</string>
|
||||
<string name="su_allow_toast">Pro %1$s bylo oprávnění Superuser povoleno</string>
|
||||
<string name="su_deny_toast">Pro %1$s bylo oprávnění Superuser zamítnuto</string>
|
||||
<string name="no_apps_found">Zatím zde není žádná aplikace</string>
|
||||
<string name="su_snack_grant">Superuser oprávnění pro %1$s je povoleno</string>
|
||||
<string name="su_snack_deny">Superuser oprávnění pro %1$s je zamítnuto</string>
|
||||
<string name="su_snack_notif_on">Oznámení pro %1$s je povoleno</string>
|
||||
<string name="su_snack_notif_off">Oznámení pro %1$s je zakázáno</string>
|
||||
<string name="su_snack_log_on">Logování %1$s je povoleno</string>
|
||||
<string name="su_snack_log_off">Logování %1$s je zakázáno</string>
|
||||
<string name="su_snack_revoke">Záznamy oprávnění %1$s jsou smazány</string>
|
||||
<string name="su_revoke_title">Smazat?</string>
|
||||
<string name="su_revoke_msg">Smazat záznam ohledně oprávnění pro %1$s?</string>
|
||||
<string name="toast">Toast</string>
|
||||
<string name="none">Žádné</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID:\u0020</string>
|
||||
<string name="target_uid">Cílové UID:\u0020</string>
|
||||
<string name="command">Příkaz:\u0020</string>
|
||||
|
||||
</resources>
|
@@ -1,223 +0,0 @@
|
||||
<resources>
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="modules">Module</string>
|
||||
<string name="downloads">Downloads</string>
|
||||
<string name="superuser">Superuser</string>
|
||||
<string name="log">Log</string>
|
||||
<string name="settings">Einstellungen</string>
|
||||
<string name="install">Installieren</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version_error">Magisk ist nicht installiert</string>
|
||||
<string name="checking_for_updates">Suche nach Aktualisierungen...</string>
|
||||
<string name="magisk_update_available">Magisk %1$s ist verfügbar!</string>
|
||||
<string name="invalid_update_channel">Ungültiger Aktualisierungskanal</string>
|
||||
<string name="safetyNet_check_text">SafetyNet-Status abfragen</string>
|
||||
<string name="checking_safetyNet_status">Prüfe SafetyNet-Status...</string>
|
||||
<string name="safetyNet_check_success">SafetyNet-Test erfolgreich</string>
|
||||
<string name="safetyNet_api_error">SafetyNet API Fehler</string>
|
||||
<string name="safetyNet_res_invalid">Die Antwort ist ungültig</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="advanced_settings_title">Erweiterte Optionen</string>
|
||||
<string name="keep_force_encryption">\"force encryption\" beibehalten</string>
|
||||
<string name="keep_dm_verity">AVB 2.0/dm-verity beibehalten</string>
|
||||
<string name="current_magisk_title">Installierte Version: %1$s</string>
|
||||
<string name="install_magisk_title">Neueste Version: %1$s</string>
|
||||
<string name="uninstall">Deinstallieren</string>
|
||||
<string name="uninstall_magisk_title">Magisk deinstallieren</string>
|
||||
<string name="uninstall_magisk_msg">Alle Module werden deaktiviert/entfernt. Root wird entfernt und möglicherweise werden Ihre Daten verschlüsseln, falls Ihre Daten derzeit nicht verschlüsselt sind.</string>
|
||||
<string name="update">Aktualisierung %1$s</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Nichts angegeben)</string>
|
||||
<string name="no_modules_found">Keine Module gefunden</string>
|
||||
<string name="update_file_created">Modul wird beim nächsten Neustart aktualisiert</string>
|
||||
<string name="remove_file_created">Modul wird beim nächsten Neustart entfernt</string>
|
||||
<string name="remove_file_deleted">Modul wird beim nächsten Neustart nicht entfernt</string>
|
||||
<string name="disable_file_created">Modul wird beim nächsten Neustart deaktiviert</string>
|
||||
<string name="disable_file_removed">Modul wird beim nächsten Neustart aktiviert</string>
|
||||
<string name="author">Erstellt von %1$s</string>
|
||||
<string name="reboot_recovery">Neustart in das Recovery</string>
|
||||
<string name="reboot_bootloader">Neustart in den Bootloader</string>
|
||||
<string name="reboot_download">Neustart in den Download-Modus</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Aktualisierung verfügbar</string>
|
||||
<string name="installed">Installiert</string>
|
||||
<string name="not_installed">Nicht installiert</string>
|
||||
<string name="updated_on">Zuletzt aktualisiert: %1$s</string>
|
||||
<string name="sorting_order">Sortierung</string>
|
||||
<string name="sort_by_name">Nach Namen sortiert</string>
|
||||
<string name="sort_by_update">Nach Aktualisierungsdatum sortiert</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveLog">Log speichern</string>
|
||||
<string name="menuReload">Log erneut laden</string>
|
||||
<string name="menuClearLog">Log löschen</string>
|
||||
<string name="logs_cleared">Log gelöscht</string>
|
||||
<string name="log_is_empty">Log ist leer</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">Info</string>
|
||||
<string name="app_changelog">Änderungsprotokoll</string>
|
||||
<string name="translators">skalnet, c727, jenslody, SuperSandro2000</string>
|
||||
<string name="app_version">Version</string>
|
||||
<string name="app_source_code">Quelltext</string>
|
||||
<string name="donation">Spenden</string>
|
||||
<string name="app_translators">Übersetzer</string>
|
||||
<string name="support_thread">Hilfeforum</string>
|
||||
<string name="follow_twitter">Folge mir auf Twitter</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="close">Schließen</string>
|
||||
<string name="repo_install_title">Installiere %1$s</string>
|
||||
<string name="repo_install_msg">Möchtest du %1$s installieren?</string>
|
||||
<string name="download">Herunterladen</string>
|
||||
<string name="reboot">Neustart</string>
|
||||
<string name="magisk_update_title">Neue Magisk Update verfügbar!</string>
|
||||
<string name="settings_reboot_toast">Neustarten, um die Änderungen zu übernehmen</string>
|
||||
<string name="release_notes">Versionshinweise</string>
|
||||
<string name="repo_cache_cleared">Repo-Cache geleert</string>
|
||||
<string name="process_error">Prozessfehler</string>
|
||||
<string name="internal_storage">Die Zip-Datei ist gespeichert unter:\n[Interner Speicher]%1$s</string>
|
||||
<string name="zip_download_title">Herunterladen</string>
|
||||
<string name="zip_download_msg">Lade Zip-Datei herunter (%1$d%%) …</string>
|
||||
<string name="zip_process_title">Verarbeite</string>
|
||||
<string name="zip_process_msg">Verarbeite Zip-Datei…</string>
|
||||
<string name="manager_update_title">Aktualisierung für Magisk Manager verfügbar!</string>
|
||||
<string name="manager_download_install">Herunterladen und installieren</string>
|
||||
<string name="dtbo_patched_title">DTBO wurde gepatched!</string>
|
||||
<string name="dtbo_patched_reboot">Magisk Manager hat dtbo.img gepatched, bitte neustarten</string>
|
||||
<string name="magisk_updates">Magisk Update</string>
|
||||
<string name="flashing">Flashing</string>
|
||||
<string name="hide_manager_toast">Verberge Magisk Manager…</string>
|
||||
<string name="hide_manager_toast2">Das könnte einige Zeit dauern...</string>
|
||||
<string name="hide_manager_fail_toast">Verbergen von Magisk Manager fehlgeschlagen…</string>
|
||||
<string name="open_link_failed_toast">Es wurde keine Anwendung gefunden, um diesen Link zu öffnen...</string>
|
||||
<string name="download_zip_only">Nur Zip-Datei herunterladen</string>
|
||||
<string name="patch_boot_file">Boot-Image-Datei patchen</string>
|
||||
<string name="direct_install">Direkt installieren (empfohlen)</string>
|
||||
<string name="install_inactive_slot">Installiere auf inaktiven Slot (Nach OTA)</string>
|
||||
<string name="warning">Warnung</string>
|
||||
<string name="install_inactive_slot_msg">Dein Gerät wird GEZWUNGEN in den aktuell inaktiven Slot zu starten, nachdem nach dem ein Neustart durchgeführt wurde!\nBenutze diese Option nur, nachdem das OTA beendet wurde.\nFortsetzen?</string>
|
||||
<string name="select_method">Methode auswählen</string>
|
||||
<string name="no_boot_file_patch_support">Magisk Zielversion unterstützt das Patchen von Boot-Images nicht</string>
|
||||
<string name="boot_file_patch_msg">Wähle das original Boot-Image-Dump im Format .img oder .img.tar</string>
|
||||
<string name="complete_uninstall">Komplette Deinstallation</string>
|
||||
<string name="restore_img">Images wiederherstellen</string>
|
||||
<string name="restore_img_msg">Wiederherstellen...</string>
|
||||
<string name="restore_done">Wiederherstellung erfolgreich!</string>
|
||||
<string name="restore_fail">Kein Original Backup vorhanden!</string>
|
||||
<string name="proprietary_title">Lade proprietären Code herunter</string>
|
||||
<string name="proprietary_notice">Magisk Manager ist FOSS und enthält keinen proprietären SafetyNet API Code von Google. Magisk Manager erlauben eine Erweiterung (enthält GoogleApiClient) für SafetyNet-Checks herunterzuladen?</string>
|
||||
<string name="su_db_corrupt">SU-Datenbank ist fehlerhaft, es wird eine neue erstellt</string>
|
||||
<string name="setup_done">Einrichtung abgeschlossen</string>
|
||||
<string name="setup_fail">Einrichtung fehlgeschlagen</string>
|
||||
<string name="env_fix_title">Zusätzliche Einrichtung erforderlich</string>
|
||||
<string name="env_fix_msg">Ihr Gerät benötigt zusätzliche Einrichtung, damit Magisk ordnungsgemäß funktioniert. Es wird eine Magisk-Installations-Zip wird heruntergeladen, fortfahren?</string>
|
||||
<string name="setup_title">Zusätzliche Einrichtung</string>
|
||||
<string name="setup_msg">Umgebungseinrichtung läuft…</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Allgemein</string>
|
||||
<string name="settings_dark_theme_title">Dunkles Theme</string>
|
||||
<string name="settings_dark_theme_summary">Dunkles Theme aktivieren</string>
|
||||
<string name="settings_clear_cache_title">Repo-Cache leeren</string>
|
||||
<string name="settings_clear_cache_summary">Löscht die zwischengespeicherten Informationen des Online-Repos. Erzwingt eine Aktualisierung</string>
|
||||
<string name="settings_hide_manager_title">Magisk Manager verbergen</string>
|
||||
<string name="settings_hide_manager_summary">Magisk Manager mit zufälligem Paketnamen neu packen</string>
|
||||
<string name="settings_restore_manager_title">Magisk Manager wiederherstellen</string>
|
||||
<string name="settings_restore_manager_summary">Stellt Magisk Manager mit ursprünglichem Paketnamen wieder her</string>
|
||||
<string name="language">Sprache</string>
|
||||
<string name="system_default">(Systemstandard)</string>
|
||||
<string name="settings_update">Aktualisierungs-Einstellungen</string>
|
||||
<string name="settings_check_update_title">Prüfe nach Aktualisierungen</string>
|
||||
<string name="settings_check_update_summary">Prüfe regelmäßig im Hintergrund nach Aktualisierungen</string>
|
||||
<string name="settings_update_channel_title">Aktualisierungs-Kanal</string>
|
||||
<string name="settings_update_stable">Stabil</string>
|
||||
<string name="settings_update_beta">Beta</string>
|
||||
<string name="settings_update_custom">Benutzerdefiniert</string>
|
||||
<string name="settings_update_custom_msg">Gib eine benutzerdefinierte URL ein</string>
|
||||
<string name="settings_boot_format_title">Ausgabeformat des gepatchten Boot-Images</string>
|
||||
<string name="settings_boot_format_summary">Wähle das Ausgabeformat des gepatchten Boot-Images.\nWähle .img, um mit \"fastboot/download mode\" zu flashen; wähle .img.tar zum Flashen mit ODIN.</string>
|
||||
<string name="settings_core_only_title">Nur Kernfunktionen</string>
|
||||
<string name="settings_core_only_summary">Aktiviert lediglich die Kernfunktionen, Module werden nicht geladen. MagiskSU, Magisk Hide und Systemless hosts bleiben weiterhin aktiv</string>
|
||||
<string name="settings_magiskhide_summary">Versteckt Magisk vor diversen Entdeckungsmethoden</string>
|
||||
<string name="settings_hosts_title">Systemlose Hosts-Datei</string>
|
||||
<string name="settings_hosts_summary">Systemlose Unterstützung für Werbeblocker</string>
|
||||
|
||||
<string name="settings_su_app_adb">Apps und ADB</string>
|
||||
<string name="settings_su_app">Nur Apps</string>
|
||||
<string name="settings_su_adb">Nur ADB</string>
|
||||
<string name="settings_su_disable">Deaktiviert</string>
|
||||
<string name="settings_su_request_10">10 Sekunden</string>
|
||||
<string name="settings_su_request_20">20 Sekunden</string>
|
||||
<string name="settings_su_request_30">30 Sekunden</string>
|
||||
<string name="settings_su_request_60">60 Sekunden</string>
|
||||
<string name="superuser_access">Superuser-Zugriff</string>
|
||||
<string name="auto_response">Automatisch beantworten</string>
|
||||
<string name="request_timeout">Zeitlimit für Anfrage</string>
|
||||
<string name="superuser_notification">Superuser-Benachrichtigung</string>
|
||||
<string name="request_timeout_summary">%1$s Sekunden</string>
|
||||
<string name="settings_su_reauth_title">Nach Aktualisierung erneut authentifizieren</string>
|
||||
<string name="settings_su_reauth_summary">Superuser-Zugriff nach App-Aktualisierung erneut abfragen</string>
|
||||
<string name="settings_su_fingerprint_title">Aktiviere Authentifizierung durch Fingerabdruck</string>
|
||||
<string name="settings_su_fingerprint_summary">Fingerabdrucksensor benutzen um Superuser-Anfragen zu erlauben</string>
|
||||
<string name="auth_fingerprint">Authentifiziere Fingerabdruck</string>
|
||||
|
||||
<string name="multiuser_mode">Mehrbenutzermodus</string>
|
||||
<string name="settings_owner_only">Nur der Gerätebesitzer</string>
|
||||
<string name="settings_owner_manage">Durch Gerätebesitzer verwaltet</string>
|
||||
<string name="settings_user_independent">Benutzerunabhängig</string>
|
||||
<string name="owner_only_summary">Nur der Besitzer hat Root-Zugriff</string>
|
||||
<string name="owner_manage_summary">Nur der Besitzer verwaltet den Root-Zugriff und erhält Zugriffs-Anfragen</string>
|
||||
<string name="user_indepenent_summary">Jeder Nutzer hat seine eingenen Root-Regeln</string>
|
||||
<string name="multiuser_hint_owner_request">Eine Anfrage wurde an den Gerätebesitzer gesendet. Bitte wechsel zum Bersitzerkonto und gewähre die Rechte.</string>
|
||||
|
||||
<string name="mount_namespace_mode">Mount-Namespace-Modus</string>
|
||||
<string name="settings_ns_global">Globaler Namespace</string>
|
||||
<string name="settings_ns_requester">Geerbter Namespace</string>
|
||||
<string name="settings_ns_isolate">Isolierter Namespace</string>
|
||||
<string name="global_summary">Alle Root-Sitzungen benutzen den global angelegten Namespace</string>
|
||||
<string name="requester_summary">Root-Sitzungen erben den Namespace des Abfragenden</string>
|
||||
<string name="isolate_summary">Jede Root-Sitzung hat ihren isolierten Namespace</string>
|
||||
<string name="android_o_not_support">Android 8.0+ wird nicht unterstützt</string>
|
||||
<string name="disable_fingerprint">Keine Fingerabdrücke gespeichert oder keine Geräteunterstützung</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Superuser-Anfrage</string>
|
||||
<string name="deny_with_str">Verweigern%1$s</string>
|
||||
<string name="deny">Verweigern</string>
|
||||
<string name="prompt">Nachfragen</string>
|
||||
<string name="grant">Gewähren</string>
|
||||
<string name="su_warning">Erlaubt den vollen Zugriff auf das Gerät.\nVerweigere, wenn du dir unsicher bist!</string>
|
||||
<string name="forever">Dauerhaft</string>
|
||||
<string name="once">Einmalig</string>
|
||||
<string name="tenmin">10 Min.</string>
|
||||
<string name="twentymin">20 Min.</string>
|
||||
<string name="thirtymin">30 Min.</string>
|
||||
<string name="sixtymin">60 Min.</string>
|
||||
<string name="su_allow_toast">Superuser-Rechte für %1$s gewährt</string>
|
||||
<string name="su_deny_toast">Superuser-Rechte für %1$s verweigert</string>
|
||||
<string name="no_apps_found">Keine Apps gefunden</string>
|
||||
<string name="su_snack_grant">Superuser-Rechte werden für %1$s gewährt</string>
|
||||
<string name="su_snack_deny">Superuser-Rechte werden für %1$s verweigert</string>
|
||||
<string name="su_snack_notif_on">Benachrichtigungen sind für %1$s aktiviert</string>
|
||||
<string name="su_snack_notif_off">Benachrichtigungen sind für %1$s deaktiviert</string>
|
||||
<string name="su_snack_log_on">Logging ist für %1$s aktiviert</string>
|
||||
<string name="su_snack_log_off">Logging ist für %1$s deaktiviert</string>
|
||||
<string name="su_snack_revoke">Die Rechte für %1$s wurden entzogen</string>
|
||||
<string name="su_revoke_title">Entziehen?</string>
|
||||
<string name="su_revoke_msg">Möchtest du die Rechte für %1$s entziehen?</string>
|
||||
<string name="toast">Popup</string>
|
||||
<string name="none">Keine</string>
|
||||
<string name="auth_fail">Authentifizierung fehlgeschlagen</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID:\u0020</string>
|
||||
<string name="target_uid">Ziel-UID:\u0020</string>
|
||||
<string name="command">Befehl:\u0020</string>
|
||||
|
||||
</resources>
|
@@ -1,201 +0,0 @@
|
||||
<resources>
|
||||
<!--Welcome Activity-->
|
||||
<string name="modules">Modules</string>
|
||||
|
||||
<string name="downloads">Λήψεις</string>
|
||||
<string name="superuser">Υπερχρήστης</string>
|
||||
<string name="log">Αρχείο Καταγραφής</string>
|
||||
<string name="settings">Ρυθμίσεις</string>
|
||||
<string name="install">Εγκατάσταση</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version_error">Το Magisk δεν είναι εγκατεστημένο</string>
|
||||
|
||||
<string name="checking_for_updates">Έλεγχος για ενημερώσεις…</string>
|
||||
<string name="magisk_update_available">Το Magisk v%1$s είναι διαθέσιμο!</string>
|
||||
<string name="invalid_update_channel">Λανθασμένο κανάλι ενημέρωσης</string>
|
||||
<string name="safetyNet_check_text">Πατήστε για έλεγχο του SafetyNet</string>
|
||||
<string name="checking_safetyNet_status">Έλεγχος κατάστασης SafetyNet…</string>
|
||||
<string name="safetyNet_check_success">Ο Έλεγχος του SafetyNet Ήταν Επιτυχής</string>
|
||||
<string name="safetyNet_api_error">Σφάλμα του SafetyNet API</string>
|
||||
<string name="safetyNet_res_invalid">Η απόκριση είναι άκυρη</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="advanced_settings_title">Προηγμένες ρυθμίσεις</string>
|
||||
<string name="keep_force_encryption">Διατήρηση επιβεβλημένης κρυπτογράφησης</string>
|
||||
<string name="keep_dm_verity">Διατήρηση dm-verity</string>
|
||||
<string name="current_magisk_title">Εγκατεστημένη έκδοση: %1$s</string>
|
||||
<string name="install_magisk_title">Τελευταία έκδοση: %1$s</string>
|
||||
<string name="uninstall">Απεγκατάσταση</string>
|
||||
<string name="uninstall_magisk_title">Απεγκατάσταση Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Όλα τα modules θα απενεργοποιηθούν/αφαιρεθούν. Το root θα αφαιρεθεί και ενδέχεται να κρυπτογραφηθούν τα δεδομένα σας, εάν δεν είναι κρυπτογραφημένα</string>
|
||||
<string name="update">Ενημέρωση %1$s</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Δεν δόθηκαν πληροφορίες)</string>
|
||||
<string name="no_modules_found">Δεν βρέθηκαν modules</string>
|
||||
<string name="update_file_created">Η ενότητα θα ενημερωθεί στην επόμενη επανεκκίνηση</string>
|
||||
<string name="remove_file_created">Η ενότητα θα αφαιρεθεί στην επόμενη επανεκκίνηση</string>
|
||||
<string name="remove_file_deleted">Η ενότητα δεν θα αφαιρεθεί στην επόμενη επανεκκίνηση</string>
|
||||
<string name="disable_file_created">Η ενότητα θα απενεργοποιηθεί στην επόμενη επανεκκίνηση</string>
|
||||
<string name="disable_file_removed">Η ενότητα θα ενεργοποιηθεί στην επόμενη επανεκκίνηση</string>
|
||||
<string name="author">Δημιουργήθηκε από τον/την %1$s</string>
|
||||
<string name="reboot_recovery">Επανεκκίνηση στο Recovery</string>
|
||||
<string name="reboot_bootloader">Επανεκκίνηση στο Bootloader</string>
|
||||
<string name="reboot_download">Επανεκκίνηση για λήψη</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Διαθέσιμη Ενημέρωση</string>
|
||||
<string name="installed">Εγκαταστάθηκε</string>
|
||||
<string name="not_installed">Μη εγκατεστημένη</string>
|
||||
<string name="updated_on">Αναβαθμίστηκε στις: %1$s</string>
|
||||
<string name="sorting_order">Ταξινόμηση κατά</string>
|
||||
<string name="sort_by_name">Ταξινόμηση κατά όνομα</string>
|
||||
<string name="sort_by_update">Ταξινόμηση κατά τελευταία αναβάθμιση</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveLog">"Αποθήκευση καταγραφής "</string>
|
||||
<string name="menuReload">Επαναφόρτωση</string>
|
||||
<string name="menuClearLog">Εκκαθάριση αρχείου καταγραφής τώρα</string>
|
||||
<string name="logs_cleared">Το αρχείο καταγραφής εκκαθαρίστηκε επιτυχώς</string>
|
||||
<string name="log_is_empty">Το αρχείο καταγραφής είναι κενό</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">Περί</string>
|
||||
<string name="app_changelog">Καταγραφή αλλαγών εφαρμογής</string>
|
||||
<string name="translators">GreatApo, JpegXguy</string>
|
||||
<string name="app_version">Έκδοση εφαρμογής</string>
|
||||
<string name="app_source_code">Πηγαίος κώδικας</string>
|
||||
<string name="donation">Δωρεά</string>
|
||||
<string name="app_translators">Μεταφραστές εφαρμογής</string>
|
||||
<string name="support_thread">Σύνδεσμος υποστήριξης</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="close">Κλείσιμο</string>
|
||||
<string name="repo_install_title">Εγκατάσταση %1$s</string>
|
||||
<string name="repo_install_msg">Θέλετε να εγκαταστήσετε το %1$s τώρα;</string>
|
||||
<string name="download">Λήψη</string>
|
||||
<string name="reboot">Επανεκκίνηση</string>
|
||||
<string name="magisk_update_title">Νέα Ενημέρωση Magisk Διαθέσιμη!</string>
|
||||
<string name="settings_reboot_toast">Επανεκκίνηση για εφαρμογή ρυθμίσεων</string>
|
||||
<string name="release_notes">Σημειώσεις έκδοσης</string>
|
||||
<string name="repo_cache_cleared">Η Repo cache καθαρίστηκε</string>
|
||||
<string name="process_error">Σφάλμα διαδικασίας</string>
|
||||
<string name="internal_storage">Το zip είναι αποθηκευμένο σε:\n[Εσωτερική μνήμη]%1$s</string>
|
||||
<string name="zip_download_title">Γίνεται λήψη</string>
|
||||
<string name="zip_download_msg">Λήψη αρχείου zip (%1$d%%) …</string>
|
||||
<string name="zip_process_title">Γίνεται επεξεργασία</string>
|
||||
<string name="zip_process_msg">Επεξεργασία αρχείου zip …</string>
|
||||
<string name="manager_update_title">Νέα Ενημέρωση Magisk Manager Διαθέσιμη!</string>
|
||||
<string name="manager_download_install">Πιέστε για λήψη και εγκατάσταση</string>
|
||||
<string name="dtbo_patched_title">Έγινε patch στο DTBO!</string>
|
||||
<string name="dtbo_patched_reboot">Το Magisk Manager έκανε patch το dtbo.img, παρακαλώ κάντε επανεκκίνηση</string>
|
||||
<string name="magisk_updates">Ενημερώσεις Magisk</string>
|
||||
<string name="flashing">Γίνεται flash</string>
|
||||
<string name="hide_manager_toast">Κρύβοντας το Magisk Manager…</string>
|
||||
<string name="hide_manager_toast2">Αυτό μπορεί να πάρει λίγη ώρα…</string>
|
||||
<string name="hide_manager_fail_toast">Η απόκρυψη του Magisk Manager απέτυχε…</string>
|
||||
<string name="download_zip_only">Λήψη Zip Μόνο</string>
|
||||
<string name="patch_boot_file">Εφαρμογή Patch στο Αρχείο Εικόνας Boot</string>
|
||||
<string name="direct_install">Απευθείας Εγκατάσταση (Προτείνεται)</string>
|
||||
<string name="select_method">Επιλογή Μεθόδου</string>
|
||||
<string name="no_boot_file_patch_support">Αυτή η Magisk έκδοση δεν υποστηρίζει patch του boot image αρχείου</string>
|
||||
<string name="boot_file_patch_msg">Επιλογή stock boot image dump σε μορφή .img ή .img.tar</string>
|
||||
<string name="complete_uninstall">Πλήρης απεγκατάσταση</string>
|
||||
<string name="restore_done">Η ανάκτηση έγινε!</string>
|
||||
<string name="restore_fail">Δεν υπάρχει αντίγραφο ασφαλείας!</string>
|
||||
<string name="proprietary_title">Λήψη Ιδιόκτητου Κώδικα</string>
|
||||
<string name="proprietary_notice">Το Magisk Manager είναι FOSS οπότε δεν περιέχει της Google τον ιδιόκτητο κώδικα του SafetyNet API.\n\nΕπιτρέπετε στο Magisk Manager να κατεβάσει μια επέκταση (περιέχει το GoogleApiClient) για ελέγχους του SafetyNet?</string>
|
||||
<string name="su_db_corrupt">Η βάση δεδομένων SU είναι κατεστραμμένη, θα αναδημιουργηθεί νέα</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Γενικά</string>
|
||||
<string name="settings_dark_theme_title">Σκούρο θέμα</string>
|
||||
<string name="settings_dark_theme_summary">Ενεργοποίηση σκούρου θέματος</string>
|
||||
<string name="settings_clear_cache_title">Εκκαθάριση προσωρινής μνήμης αποθετηρίων</string>
|
||||
<string name="settings_clear_cache_summary">Καθαρίζει τις κρυφές πληροφορίες για απευθείας συνδεδεμένα αποθετήρια, αναγκάζει την εφαρμογή να κάνει ανανέωση σε απευθείας σύνδεση</string>
|
||||
<string name="settings_hide_manager_title">Απόκρυψη του Magisk Manager</string>
|
||||
<string name="settings_hide_manager_summary">Ανασυγκρότηση του Magisk Manager με τυχαίο όνομα πακέτου</string>
|
||||
<string name="language">Γλώσσα</string>
|
||||
<string name="system_default">(Προεπιλογή Συστήματος)</string>
|
||||
<string name="settings_update">Ρυθμίσεις Ενημερώσεων</string>
|
||||
<string name="settings_update_channel_title">Κανάλι Ενημερώσεων</string>
|
||||
<string name="settings_update_stable">Σταθερό</string>
|
||||
<string name="settings_update_beta">Δοκιμαστικό</string>
|
||||
<string name="settings_update_custom">Custom</string>
|
||||
<string name="settings_update_custom_msg">Εισαγωγή ενός custom URL</string>
|
||||
<string name="settings_boot_format_title">Μορφή Τροποποιημένης Εικόνας Boot</string>
|
||||
<string name="settings_boot_format_summary">Επιλέξτε τη μορφή της εξαγόμενης εικόνας boot μετά το patch.\nΕπιλέξτε .img για flash μέσω λειτουργίας fastboot/download· επιλέξτε .img.tar για flash μέσω ODIN.</string>
|
||||
<string name="settings_core_only_title">Magisk Λειτουργία Πυρήνα Μόνο</string>
|
||||
<string name="settings_core_only_summary">Ενεργοποίηση μόνο των λειτουργιών πυρήνα, καμία από τις ενότητες δεν θα ενεργοποιηθεί. Τα MagiskSU, MagiskHide, και systemless hosts θα παραμείνουν ενεργά</string>
|
||||
<string name="settings_magiskhide_summary">Κρύβει το Magisk από διάφορες ανιχνεύσεις</string>
|
||||
<string name="settings_hosts_title">Systemless hosts</string>
|
||||
<string name="settings_hosts_summary">Υποστήριξη Systemless hosts για εφαρμογές Adblock</string>
|
||||
|
||||
<string name="settings_su_app_adb">Εφαρμογές και ADB</string>
|
||||
<string name="settings_su_app">Εφαρμογές μόνο</string>
|
||||
<string name="settings_su_adb">ADB μόνο</string>
|
||||
<string name="settings_su_disable">Απενεργοποιημένο</string>
|
||||
<string name="settings_su_request_10">10 δευτερόλεπτα</string>
|
||||
<string name="settings_su_request_20">20 δευτερόλεπτα</string>
|
||||
<string name="settings_su_request_30">30 δευτερόλεπτα</string>
|
||||
<string name="settings_su_request_60">60 δευτερόλεπτα</string>
|
||||
<string name="superuser_access">Πρόσβαση Υπερχρήστη</string>
|
||||
<string name="auto_response">Αυτόματη Απόκριση</string>
|
||||
<string name="request_timeout">Χρονικό όριο Αιτήματος</string>
|
||||
<string name="superuser_notification">Ειδοποίηση Υπερχρήστη</string>
|
||||
<string name="request_timeout_summary">%1$s δευτερόλεπτα</string>
|
||||
<string name="settings_su_reauth_title">Επαναπιστοποίηση μετά από αναβάθμιση</string>
|
||||
<string name="settings_su_reauth_summary">Επαναπιστοποίηση αδειών υπερχρήστη μετά την αναβάθμιση μίας εφαρμογής</string>
|
||||
|
||||
<string name="multiuser_mode">Λειτουργία Πολλών Χρηστών</string>
|
||||
<string name="settings_owner_only">Μόνο Ιδιοκτήτης Συσκευής</string>
|
||||
<string name="settings_owner_manage">Διαχειριζόμενη από τον Ιδιοκτήτη</string>
|
||||
<string name="settings_user_independent">Ανεξάρτητη από τον χρήστη</string>
|
||||
<string name="owner_only_summary">Μόνο ο ιδιοκτήτης έχει πρόσβαση root</string>
|
||||
<string name="owner_manage_summary">Μόνο ο ιδιοκτήτης μπορεί να διαχειριστεί την πρόσβαση root και να δεχτεί προτροπές αίτημάτων</string>
|
||||
<string name="user_indepenent_summary">Κάθε χρήστης έχει τους δικούς του ξεχωριστούς κανόνες root</string>
|
||||
<string name="multiuser_hint_owner_request">Ένα αίτημα έχει σταλεί στον ιδιοκτήτη της συσκευής. Παρακαλώ αλλάξτε σε ιδιοκτήτη και δώστε την άδεια</string>
|
||||
|
||||
<string name="mount_namespace_mode">Λειτουργία προσάρτησης χώρου ονομάτων</string>
|
||||
<string name="settings_ns_global">Καθολικός Χώρος Ονομάτων</string>
|
||||
<string name="settings_ns_requester">Κληρονόμησε Χώρο Ονομάτων</string>
|
||||
<string name="settings_ns_isolate">Απομονωμένος Χώρος Ονομάτων</string>
|
||||
<string name="global_summary">Όλες οι συνεδρίες root χρησιμοποιούν τον καθολικό χώρο oνομάτων προσάρτησης</string>
|
||||
<string name="requester_summary">Οι συνεδρίες root θα κληρονομούν το χώρο ονομάτων του αιτούντα τους</string>
|
||||
<string name="isolate_summary">Κάθε συνεδρία root θα έχει το δικό της απομονωμένο χώρο ονομάτων</string>
|
||||
<string name="android_o_not_support">Δεν υποστηρίζεται Android 8.0+</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Αίτημα υπερχρήστη</string>
|
||||
<string name="deny_with_str">Άρνηση%1$s</string>
|
||||
<string name="deny">Άρνηση</string>
|
||||
<string name="prompt">Προτροπή</string>
|
||||
<string name="grant">Αποδοχή</string>
|
||||
<string name="su_warning">Δίνει πλήρη πρόσβαση στη συσκευή σας.\nΑρνηθείτε αν δεν είστε σίγουρος/η!</string>
|
||||
<string name="forever">Πάντα</string>
|
||||
<string name="once">Μία φορά</string>
|
||||
<string name="tenmin">10 λεπτά</string>
|
||||
<string name="twentymin">20 λεπτά</string>
|
||||
<string name="thirtymin">30 λεπτά</string>
|
||||
<string name="sixtymin">60 λεπτά</string>
|
||||
<string name="su_allow_toast">Παραχωρήθηκαν δικαιώματα υπερχρήστη στο %1$s</string>
|
||||
<string name="su_deny_toast">Απορρίφθηκαν τα δικαιώματα υπερχρήστη του %1$s</string>
|
||||
<string name="no_apps_found">Δεν βρέθηκαν εφαρμογές</string>
|
||||
<string name="su_snack_grant">Παραχορούνται δικαιώματα υπερχρήστη στο %1$s</string>
|
||||
<string name="su_snack_deny">Δεν παραχορούνται δικαιώματα υπερχρήστη στο %1$s</string>
|
||||
<string name="su_snack_notif_on">Οι ειδοποιήσεις του %1$s είναι ενεργοποιημένες</string>
|
||||
<string name="su_snack_notif_off">Οι ειδοποιήσεις του %1$s είναι απενεργοποιημένες</string>
|
||||
<string name="su_snack_log_on">Η καταγραφή του %1$s είναι ενεργοποιημένη</string>
|
||||
<string name="su_snack_log_off">Η καταγραφή του %1$s είναι απενεργοποιημένη</string>
|
||||
<string name="su_snack_revoke">Τα δικαιώματα του %1$s ανακαλούνται</string>
|
||||
<string name="su_revoke_title">Ανάκληση;</string>
|
||||
<string name="su_revoke_msg">Επιβεβαίωση για ανάκληση δικαιωμάτων %1$s;</string>
|
||||
<string name="toast">Αναδυόμενο παράθυρο</string>
|
||||
<string name="none">Κανένα</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID:\u0020</string>
|
||||
<string name="target_uid">UID Στόχος:\u0020</string>
|
||||
<string name="command">Εντολή:\u0020</string>
|
||||
</resources>
|
@@ -1,222 +0,0 @@
|
||||
<resources>
|
||||
<!--Universal-->
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="modules">Módulos</string>
|
||||
<string name="downloads">Descargas</string>
|
||||
<string name="superuser">Superusuario</string>
|
||||
<string name="log">Registro</string>
|
||||
<string name="settings">Ajustes</string>
|
||||
<string name="install">Instalar</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version_error">Magisk no está instalado</string>
|
||||
<string name="checking_for_updates">Comprobando Actualizaciones…</string>
|
||||
<string name="magisk_update_available">¡Disponible Magisk v%1$s!</string>
|
||||
<string name="invalid_update_channel">Canal de actualización inválido</string>
|
||||
<string name="safetyNet_check_text">Comprobar el estado de SafetyNet</string>
|
||||
<string name="checking_safetyNet_status">Comprobando estado de SafetyNet…</string>
|
||||
<string name="safetyNet_check_success">La comprobación fue exitosa</string>
|
||||
<string name="safetyNet_api_error">Error en la API de SafetyNet</string>
|
||||
<string name="safetyNet_res_invalid">La respuesta no es válida</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="advanced_settings_title">Ajustes avanzados</string>
|
||||
<string name="keep_force_encryption">Mantener cifrado forzado</string>
|
||||
<string name="keep_dm_verity">Mantener AVB 2.0/dm-verity</string>
|
||||
<string name="current_magisk_title">Versión instalada: %1$s</string>
|
||||
<string name="install_magisk_title">Última versión: %1$s</string>
|
||||
<string name="uninstall">Desinstalar</string>
|
||||
<string name="uninstall_magisk_msg">Todos los módulos serán desactivados / eliminados. El acceso Root se eliminará y, posiblemente, cifrará los datos si los datos no están cifrados actualmente.</string>
|
||||
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
|
||||
<string name="update">Actualización %1$s</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(No hay información)</string>
|
||||
<string name="no_modules_found">No se encontraron módulos</string>
|
||||
<string name="update_file_created">El módulo se actualizará en el siguiente reinicio</string>
|
||||
<string name="remove_file_created">El módulo se eliminará en el siguiente reinicio</string>
|
||||
<string name="remove_file_deleted">El módulo no se eliminará en el siguiente reinicio</string>
|
||||
<string name="disable_file_created">El módulo se desactivará en el siguiente reinicio</string>
|
||||
<string name="disable_file_removed">El módulo se activará en el siguiente reinicio</string>
|
||||
<string name="author">Creado por %1$s</string>
|
||||
<string name="reboot_recovery">Reiniciar en Modo Recovery</string>
|
||||
<string name="reboot_bootloader">Reiniciar en Modo Bootloader</string>
|
||||
<string name="reboot_download">Reiniciar en Modo Download</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Actualización Disponible</string>
|
||||
<string name="installed">Instalado</string>
|
||||
<string name="not_installed">No Instalado</string>
|
||||
<string name="updated_on">Actualizado el: %1$s</string>
|
||||
<string name="sorting_order">Orden de Clasificación</string>
|
||||
<string name="sort_by_name">Ordenar por nombre</string>
|
||||
<string name="sort_by_update">Ordenar según la última actualización</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveLog">Guardar registro</string>
|
||||
<string name="menuReload">Recargar</string>
|
||||
<string name="menuClearLog">Limpiar registro ahora</string>
|
||||
<string name="logs_cleared">Registro limpiado correctamente</string>
|
||||
<string name="log_is_empty">El registro está vacio</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">Acerca de</string>
|
||||
<string name="app_changelog">Registro de cambios</string>
|
||||
<string name="translators">dark-basic</string>
|
||||
<string name="app_version">Versión</string>
|
||||
<string name="app_source_code">Código fuente</string>
|
||||
<string name="donation">Donar</string>
|
||||
<string name="app_translators">Traductores</string>
|
||||
<string name="support_thread">Hilo de soporte</string>
|
||||
<string name="follow_twitter">Sigueme en Twitter</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="close">Cerrar</string>
|
||||
<string name="repo_install_title">Instalar %1$s</string>
|
||||
<string name="repo_install_msg">¿Quieres instalar %1$s ahora?</string>
|
||||
<string name="download">Descargar</string>
|
||||
<string name="reboot">Reiniciar</string>
|
||||
<string name="zip_process_msg">Procesando archivo zip…</string>
|
||||
<string name="magisk_update_title">¡Nueva actualización de Magisk disponible!</string>
|
||||
<string name="settings_reboot_toast">Reinicia para aplicar los ajustes</string>
|
||||
<string name="release_notes">Notas de lanzamiento</string>
|
||||
<string name="repo_cache_cleared">Caché del repositorio limpiada</string>
|
||||
<string name="process_error">Error de proceso</string>
|
||||
<string name="internal_storage">El zip es almacenado en:\n[Internal Storage]%1$s</string>
|
||||
<string name="zip_download_title">Descargando</string>
|
||||
<string name="zip_download_msg">Descargando el archivo zip (%1$d%%)…</string>
|
||||
<string name="zip_process_title">Procesando</string>
|
||||
<string name="manager_update_title">Nueva actualización de Magisk Manager disponible!</string>
|
||||
<string name="manager_download_install">Pulse para descargar e instalar</string>
|
||||
<string name="dtbo_patched_title">DTBO fue parchado!</string>
|
||||
<string name="dtbo_patched_reboot">Magisk Manager ha parcheado dtbo.img, por favor reinicia</string>
|
||||
<string name="magisk_updates">Actualización de Magisk</string>
|
||||
<string name="flashing">Flasheando</string>
|
||||
<string name="hide_manager_toast">Ocultando Magisk Manager…</string>
|
||||
<string name="hide_manager_toast2">Esto podría tomar un tiempo…</string>
|
||||
<string name="hide_manager_fail_toast">La Ocultación de Magisk Manager ha fallado…</string>
|
||||
<string name="open_link_failed_toast">No se encontró ninguna aplicación para abrir el enlace…</string>
|
||||
<string name="download_zip_only">Descargar sólo el archivo ZIP</string>
|
||||
<string name="patch_boot_file">Parcheo de la imagen boot</string>
|
||||
<string name="direct_install">Instalación Directa (Recomendado)</string>
|
||||
<string name="install_inactive_slot">Instalar en ranura inactiva (después de OTA)</string>
|
||||
<string name="select_method">Seleccionar Método</string>
|
||||
<string name="no_boot_file_patch_support">La versión de Magisk no admite el parcheo de la imagen boot</string>
|
||||
<string name="boot_file_patch_msg">Seleccione el volcado de la imagen boot en formato .img o .img.tar</string>
|
||||
<string name="complete_uninstall">Desinstalación completa</string>
|
||||
<string name="restore_img">Restaurar imágenes</string>
|
||||
<string name="restore_done">¡Restauración Terminada!</string>
|
||||
<string name="restore_img_msg">Restaurando ...</string>
|
||||
<string name="restore_fail">¡El respaldo de la imagen boot Stock no existe!</string>
|
||||
<string name="proprietary_title">Descargar Código Propietario</string>
|
||||
<string name="proprietary_notice">Magisk Manager es un Software Libre por lo que no contiene el código API de SafetyNet (Código Propietario de Google).\n\n ¿Puede permitir que Magisk Manager descargue una extensión (contiene el GoogleApiClient) para la comprobación de SafetyNet?</string>
|
||||
<string name="su_db_corrupt">La base de datos SU está dañada, se creará nueva base de datos</string>
|
||||
<string name="setup_done">Instalación Realizada</string>
|
||||
<string name="setup_fail">Instalación Fallida</string>
|
||||
<string name="env_fix_title">Se Requiere una Instalación Adicional</string>
|
||||
<string name="env_fix_msg">Su dispositivo requiere una instalación adicional para que Magisk funcione correctamente. Se descargará el zip de instalación de Magisk, desea continuar ahora?</string>
|
||||
<string name="setup_title">Configuración Adicional</string>
|
||||
<string name="setup_msg">Ejecutando Configuración de Entorno</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">General</string>
|
||||
<string name="settings_dark_theme_title">Tema oscuro</string>
|
||||
<string name="settings_dark_theme_summary">Habilitar el tema oscuro</string>
|
||||
<string name="settings_clear_cache_title">Limpiar caché del repositorio</string>
|
||||
<string name="settings_clear_cache_summary">Limpiar la información en caché para los repositorios en línea, fuerza a la aplicación a actualizar en línea</string>
|
||||
<string name="settings_hide_manager_title">Ocultar Magisk Manager</string>
|
||||
<string name="settings_hide_manager_summary">Re-empaquetar Magisk Manager con un nombre de paquete al azar</string>
|
||||
<string name="settings_restore_manager_title">Restaurar Magisk Manager</string>
|
||||
<string name="settings_restore_manager_summary">Restaura Magisk Manager con el paquete original</string>
|
||||
<string name="language">Idioma</string>
|
||||
<string name="system_default">(Idioma del sistema)</string>
|
||||
<string name="settings_update">Ajustes de Actualización</string>
|
||||
<string name="settings_check_update_title">Comprobar Actualizaciones</string>
|
||||
<string name="settings_check_update_summary">Comprobar periódicamente en segundo plano si existen actualizaciones</string>
|
||||
<string name="settings_update_channel_title">Canal de Actualización</string>
|
||||
<string name="settings_update_stable">Estable</string>
|
||||
<string name="settings_update_beta">Beta</string>
|
||||
<string name="settings_update_custom">Personalizado</string>
|
||||
<string name="settings_update_custom_msg">Insertar una URL personalizada</string>
|
||||
<string name="settings_boot_format_title">Parchear imagen boot por tipo de formato</string>
|
||||
<string name="settings_boot_format_summary">Seleccionar el formato de salida para parchear la imagen boot.\nEscoja .img para flashear mediante fastboot/download mode; escoja .img.tar para flashear con ODIN.</string>
|
||||
|
||||
<string name="settings_core_only_summary">Habilitar sólo funciones principales, no se cargarán todos los módulos. MagiskSU, MagiskHide, y Systemless Hosts seguirán habilitados</string>
|
||||
<string name="settings_magiskhide_summary">Ocultar Magisk de varias detecciones</string>
|
||||
<string name="settings_hosts_title">Systemless Hosts</string>
|
||||
<string name="settings_hosts_summary">Soporte para aplicaciones Adblock fuera de la partición system</string>
|
||||
|
||||
<string name="settings_su_app_adb">Aplicaciones y ADB</string>
|
||||
<string name="settings_su_app">Sólo aplicaciones</string>
|
||||
<string name="settings_su_adb">Sólo ADB</string>
|
||||
<string name="settings_su_disable">Deshabilitado</string>
|
||||
<string name="settings_su_request_10">10 segundos</string>
|
||||
<string name="settings_su_request_20">20 segundos</string>
|
||||
<string name="settings_su_request_30">30 segundos</string>
|
||||
<string name="settings_su_request_60">60 segundos</string>
|
||||
<string name="superuser_access">Acceso de superusuario</string>
|
||||
<string name="auto_response">Respuesta automática</string>
|
||||
<string name="request_timeout">Tiempo de petición</string>
|
||||
<string name="superuser_notification">Notificación de superusuario</string>
|
||||
<string name="request_timeout_summary">%1$s segundos</string>
|
||||
<string name="settings_su_reauth_title">Re-autenticación</string>
|
||||
<string name="settings_su_reauth_summary">Pedir permisos de superusuario nuevamente si una aplicación es actualizada o reinstalada</string>
|
||||
<string name="settings_su_fingerprint_title">Autenticación por Huella Dactilar</string>
|
||||
<string name="settings_su_fingerprint_summary">Utilizar el sensor de Huella Dactilar para permitir las solicitudes de superusuario</string>
|
||||
<string name="auth_fingerprint">Autenticar Huella Dactilar</string>
|
||||
|
||||
<string name="multiuser_mode">Modo MultiUsuario</string>
|
||||
<string name="settings_owner_only">Sólo Administrador del Dispositivo</string>
|
||||
<string name="settings_owner_manage">Administrador del Dispositivo</string>
|
||||
<string name="settings_user_independent">Usuario Independiente</string>
|
||||
<string name="owner_only_summary">Sólo el administrador tiene acceso root</string>
|
||||
<string name="owner_manage_summary">Sólo el administrador puede supervisar el acceso root y recibir solicitudes de otros usuarios</string>
|
||||
<string name="user_indepenent_summary">Cada usuario tiene separadas sus propias reglas de root </string>
|
||||
<string name="multiuser_hint_owner_request">Se ha enviado una solicitud al administrador del dispositivo. Por favor, cambie a la cuenta del administrador y conceda el permiso</string>
|
||||
|
||||
<string name="mount_namespace_mode">Montar Namespace </string>
|
||||
<string name="settings_ns_global">Global Namespace</string>
|
||||
<string name="settings_ns_requester">Heredar Namespace</string>
|
||||
<string name="settings_ns_isolate">Aislar Namespace</string>
|
||||
<string name="global_summary">Todas las sesiones de root utilizan el soporte Global Namespace</string>
|
||||
<string name="requester_summary">Las sesiones de root heredarán las peticiones Namespace</string>
|
||||
<string name="isolate_summary">Cada sesión root tendrá su propia Namespace</string>
|
||||
<string name="android_o_not_support">No es compatible con Android 8.0+</string>
|
||||
<string name="disable_fingerprint">No se establecieron huellas dactilares o no existe soporte del dispositivo</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Petición de superusuario</string>
|
||||
<string name="deny_with_str">Denegar%1$s</string>
|
||||
<string name="deny">Denegar</string>
|
||||
<string name="prompt">Preguntar</string>
|
||||
<string name="grant">Permitir</string>
|
||||
<string name="su_warning">Permite acceso total a tu dispositivo.\n¡Denegar si no está seguro!</string>
|
||||
<string name="forever">Siempre</string>
|
||||
<string name="once">Una vez</string>
|
||||
<string name="tenmin">10 min</string>
|
||||
<string name="twentymin">20 min</string>
|
||||
<string name="thirtymin">30 min</string>
|
||||
<string name="sixtymin">60 min</string>
|
||||
<string name="su_allow_toast">Permitidos derechos de superusuario para %1$s</string>
|
||||
<string name="su_deny_toast">Denegados derechos de superusuario para %1$s</string>
|
||||
<string name="no_apps_found">No se encontraron aplicaciones</string>
|
||||
<string name="su_snack_grant">Derechos de superusuario para %1$s permitidos</string>
|
||||
<string name="su_snack_deny">Derechos de superusuario para %1$s denegados</string>
|
||||
<string name="su_snack_notif_on">Notificaciones de %1$s habilitadas</string>
|
||||
<string name="su_snack_notif_off">Notificaciones de %1$s deshabilitadas</string>
|
||||
<string name="su_snack_log_on">Registros de %1$s habilitados</string>
|
||||
<string name="su_snack_log_off">Registros de %1$s deshabilitados</string>
|
||||
<string name="su_snack_revoke">Anulados derechos de %1$s</string>
|
||||
<string name="su_revoke_title">¿Revocar?</string>
|
||||
<string name="su_revoke_msg">¿Confirmar para revocar derechos de %1$s?</string>
|
||||
<string name="toast">Aviso</string>
|
||||
<string name="none">Nada</string>
|
||||
<string name="auth_fail">Autenticación fallida</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID:\u0020</string>
|
||||
<string name="target_uid">UID de objetivo:\u0020</string>
|
||||
<string name="command">Comando:\u0020</string>
|
||||
|
||||
</resources>
|
@@ -1,218 +0,0 @@
|
||||
<resources>
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="modules">Moodulid</string>
|
||||
<string name="downloads">Allalaadimised</string>
|
||||
<string name="superuser">Superkasutaja</string>
|
||||
<string name="log">Logi</string>
|
||||
<string name="settings">Seaded</string>
|
||||
<string name="install">Installi</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version_error">Magisk pole installitud</string>
|
||||
<string name="checking_for_updates">Kontrollin uuendusi…</string>
|
||||
<string name="magisk_update_available">Magisk v%1$s on saadaval!</string>
|
||||
<string name="invalid_update_channel">Sobimatu uuenduste kanal</string>
|
||||
<string name="safetyNet_check_text">Koputa, et alustada SafetyNet\'i kontrolli</string>
|
||||
<string name="checking_safetyNet_status">Kontrollin SafetyNet\'i olekut…</string>
|
||||
<string name="safetyNet_check_success">SafetyNet\'i kontroll edukas</string>
|
||||
<string name="safetyNet_api_error">SafetyNet\'i API viga</string>
|
||||
<string name="safetyNet_res_invalid">Vastus on sobimatu</string>
|
||||
|
||||
<!--Install Fragment-->
|
||||
<string name="advanced_settings_title">Täpsemad seaded</string>
|
||||
<string name="keep_force_encryption">Säilita sunnitud krüpteering</string>
|
||||
<string name="keep_dm_verity">Säilita AVB 2.0/dm-verity</string>
|
||||
<string name="current_magisk_title">Installitud versioon: %1$s</string>
|
||||
<string name="install_magisk_title">Viimane versioon: %1$s</string>
|
||||
<string name="uninstall">Eemalda</string>
|
||||
<string name="uninstall_magisk_title">Eemalda Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Kõik moodulid keelatakse/eemaldatakse. Juurkasutaja eemaldatakse ning potensiaalselt krüptitakse su andmed, kui need ei ole hetkel krüpteeritud</string>
|
||||
<string name="update">Uuenda %1$s\'i</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Info puudub)</string>
|
||||
<string name="no_modules_found">Mooduleid ei leitud</string>
|
||||
<string name="update_file_created">Moodul uuendatakse järgmisel taaskäivitusel</string>
|
||||
<string name="remove_file_created">Moodul eemaldatakse järgmisel taaskäivitusel</string>
|
||||
<string name="remove_file_deleted">Moodulit ei eemaldata järgmisel taaskäivitusel</string>
|
||||
<string name="disable_file_created">Moodul keelatakse järgmisel taaskäivitusel</string>
|
||||
<string name="disable_file_removed">Moodul lubatakse järgmisel taaskäivitusel</string>
|
||||
<string name="author">Loodud %1$s poolt</string>
|
||||
<string name="reboot_recovery">Taaskäivita taastusesse</string>
|
||||
<string name="reboot_bootloader">Taaskäivita käivitushaldurisse</string>
|
||||
<string name="reboot_download">Taaskäivita allalaadimisrežiimi</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Uuendus saadaval</string>
|
||||
<string name="installed">Installitud</string>
|
||||
<string name="not_installed">Pole installitud</string>
|
||||
<string name="updated_on">Uuendatud: %1$s</string>
|
||||
<string name="sorting_order">Sorteerimisjärjekord</string>
|
||||
<string name="sort_by_name">Sorteeri nime järgi</string>
|
||||
<string name="sort_by_update">Sorteeri viimase uuenduse järgi</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveLog">Salvesta logi</string>
|
||||
<string name="menuReload">Laadi uuesti</string>
|
||||
<string name="menuClearLog">Tühjenda logi nüüd</string>
|
||||
<string name="logs_cleared">Logi edukalt tühjendatud</string>
|
||||
<string name="log_is_empty">Logi on tühi</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="about">Teave</string>
|
||||
<string name="app_changelog">Rakenduse muutuste logi</string>
|
||||
<string name="translators" />
|
||||
<string name="app_version">Rakenduse versioon</string>
|
||||
<string name="app_source_code">Lähtekood</string>
|
||||
<string name="donation">Annetus</string>
|
||||
<string name="app_translators">Rakenduse tõlkijad</string>
|
||||
<string name="support_thread">Foorumi tugiteema</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="close">Sulge</string>
|
||||
<string name="repo_install_title">Installi %1$s</string>
|
||||
<string name="repo_install_msg">Kas soovid kohe installida %1$s?</string>
|
||||
<string name="download">Allalaadimine</string>
|
||||
<string name="reboot">Taaskäivita</string>
|
||||
<string name="magisk_update_title">Magisk\'ile on uuendus saadaval!</string>
|
||||
<string name="settings_reboot_toast">Taaskäivita seadete rakendamiseks</string>
|
||||
<string name="release_notes">Väljalaskemärkmed</string>
|
||||
<string name="repo_cache_cleared">Hoidla vahemälu tühjendatud</string>
|
||||
<string name="process_error">Protsessi viga</string>
|
||||
<string name="internal_storage">ZIP on salvestatud:\n[Sisemälu]%1$s</string>
|
||||
<string name="zip_download_title">Laadin alla</string>
|
||||
<string name="zip_download_msg">Laadin ZIP-faili alla (%1$d%%)…</string>
|
||||
<string name="zip_process_title">Töötlen</string>
|
||||
<string name="zip_process_msg">Töötlen ZIP-faili…</string>
|
||||
<string name="manager_update_title">Magisk Manager\'ile on uuendus saadaval!</string>
|
||||
<string name="manager_download_install">Vajuta allalaadimiseks ja installimiseks</string>
|
||||
<string name="dtbo_patched_title">DTBO sai paigatud!</string>
|
||||
<string name="dtbo_patched_reboot">Magisk Manager on paiganud dtbo.img, palun taaskäivita</string>
|
||||
<string name="magisk_updates">Magisk\'i uuendused</string>
|
||||
<string name="flashing">Välgutamine</string>
|
||||
<string name="hide_manager_toast">Peidan Magisk Manager\'i…</string>
|
||||
<string name="hide_manager_toast2">See võib aega võtta…</string>
|
||||
<string name="hide_manager_fail_toast">Magisk Manager\'i peitmine ebaõnnestus…</string>
|
||||
<string name="download_zip_only">Laadi ainult ZIP alla</string>
|
||||
<string name="patch_boot_file">Paika käivituspildi fail</string>
|
||||
<string name="direct_install">Otsene install (soovitatud)</string>
|
||||
<string name="install_inactive_slot">Installi ebaaktiivsesse lahtrisse (pärast üle-õhu uuendust)</string>
|
||||
<string name="select_method">Vali meetod</string>
|
||||
<string name="no_boot_file_patch_support">Magisk\'i sihtversioon ei toeta käivituspildi faili paikamist</string>
|
||||
<string name="boot_file_patch_msg">Vali originaalne käivituspildi väljastus .img või .img.tar vormingus</string>
|
||||
<string name="complete_uninstall">Täielik eemaldus</string>
|
||||
<string name="restore_img">Taasta pildid</string>
|
||||
<string name="restore_img_msg">Taastamine…</string>
|
||||
<string name="restore_done">Taastus valmis!</string>
|
||||
<string name="restore_fail">Originaalne varundus puudub!</string>
|
||||
<string name="proprietary_title">Laadi alla suletud koodi</string>
|
||||
<string name="proprietary_notice">Magisk Manager on vaba ja avatud lähtekoodiga, mis ei sisalda Google\'i suletud SafetyNet\'i API koodi.\n\nKas lubad Magisk Manager\'il SafetyNet\'i kontrollide jaoks laadida alla laiendus (sisaldab GoogleApiClient\'i)?</string>
|
||||
<string name="su_db_corrupt">Superkasutaja andmebaas on korrumpeerunud, loon uue andmebaasi</string>
|
||||
<string name="setup_done">Seadistus valmis</string>
|
||||
<string name="setup_fail">Seadistus ebaõnnnestus</string>
|
||||
<string name="env_fix_title">Vajab lisaseadistust</string>
|
||||
<string name="env_fix_msg">Sinu seade vajab lisaseadistust, et Magisk töötaks korralikult. Laadime alla Magisk\'i seadistus-zip\'i, kas soovid kohe jätkata?</string>
|
||||
<string name="setup_title">Lisaseadistus</string>
|
||||
<string name="setup_msg">Käivitan keskkonnaseadistust…</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Üldine</string>
|
||||
<string name="settings_dark_theme_title">Tume teema</string>
|
||||
<string name="settings_dark_theme_summary">Luba tume teema</string>
|
||||
<string name="settings_clear_cache_title">Tühjenda hoidla vahemälu</string>
|
||||
<string name="settings_clear_cache_summary">Tühjenda võrgus olevate hoidlate vahemälus olev teave, sunnib rakendust võrgust värskendama</string>
|
||||
<string name="settings_hide_manager_title">Peida Magisk Manager</string>
|
||||
<string name="settings_hide_manager_summary">Taaspaki Magisk Manager juhusliku nimega</string>
|
||||
<string name="settings_restore_manager_title">Taasta Magisk Manager</string>
|
||||
<string name="settings_restore_manager_summary">Taasta Magisk Manageri originaalpakett</string>
|
||||
<string name="language">Keel</string>
|
||||
<string name="system_default">(Süsteemi vaikesäte)</string>
|
||||
<string name="settings_update">Uuenduste seaded</string>
|
||||
<string name="settings_check_update_title">Kontrolli uuendusi</string>
|
||||
<string name="settings_check_update_summary">Kontrolli taustal perioodiliselt uuendusi</string>
|
||||
<string name="settings_update_channel_title">Uuenduste kanal</string>
|
||||
<string name="settings_update_stable">Stabiilne</string>
|
||||
<string name="settings_update_beta">Beeta</string>
|
||||
<string name="settings_update_custom">Kohandatud</string>
|
||||
<string name="settings_update_custom_msg">Sisesta kohandatud URL</string>
|
||||
<string name="settings_boot_format_title">Paigatud käivitusväljundi vorming</string>
|
||||
<string name="settings_boot_format_summary">Vali väljutatava paigatud käivituspildi vorming.\nVali .img, mida välgutada fastboot/allalaadimisrežiimi kaudu; vali .img.tar, mida välgutada ODIN\'i kaudu.</string>
|
||||
<string name="settings_core_only_title">Magisk\'i ainult tuuma režiim</string>
|
||||
<string name="settings_core_only_summary">Luba ainult põhifunktsioonid. MagiskSU, MagiskHide ja süsteemivaba hosts siiski lubatakse, ent mooduleid ei laadita.</string>
|
||||
<string name="settings_magiskhide_summary">Peida Magisk erinevate tuvastuste eest</string>
|
||||
<string name="settings_hosts_title">Süsteemivaba hosts</string>
|
||||
<string name="settings_hosts_summary">Süsteemivaba hosts-tugi reklaamiblokeerijatest rakendustele</string>
|
||||
|
||||
<string name="settings_su_app_adb">Rakendused ja ADB</string>
|
||||
<string name="settings_su_app">Ainult rakendused</string>
|
||||
<string name="settings_su_adb">Ainult ADB</string>
|
||||
<string name="settings_su_disable">Keelatud</string>
|
||||
<string name="settings_su_request_10">10 sekundit</string>
|
||||
<string name="settings_su_request_20">20 sekundit</string>
|
||||
<string name="settings_su_request_30">30 sekundit</string>
|
||||
<string name="settings_su_request_60">60 sekundit</string>
|
||||
<string name="superuser_access">Superkasutaja ligipääs</string>
|
||||
<string name="auto_response">Automaatne vastus</string>
|
||||
<string name="request_timeout">Taotluse ajalõpp</string>
|
||||
<string name="superuser_notification">Superkasutaja teade</string>
|
||||
<string name="request_timeout_summary">%1$s sekundit</string>
|
||||
<string name="settings_su_reauth_title">Taas-autendi peale uuendust</string>
|
||||
<string name="settings_su_reauth_summary">Taas-autendi superkasutaja õigused peale rakenduse uuendust</string>
|
||||
<string name="settings_su_fingerprint_title">Luba sõrmejäljega autentimine</string>
|
||||
<string name="settings_su_fingerprint_summary">Kasuta sõrmejäljelugejat superkasutaja taotluste lubamiseks</string>
|
||||
|
||||
<string name="multiuser_mode">Mitmikkasutaja režiim</string>
|
||||
<string name="settings_owner_only">Ainult seadme omanik</string>
|
||||
<string name="settings_owner_manage">Seadme omaniku hallatud</string>
|
||||
<string name="settings_user_independent">Kasutajast sõltumatu</string>
|
||||
<string name="owner_only_summary">Ainult omanikul on juurkasutaja õigused</string>
|
||||
<string name="owner_manage_summary">Ainult omanik saab hallata juurkasutaja ligipääsu ja saada taotlusküsimusi</string>
|
||||
<string name="user_indepenent_summary">Igal kasutajal on oma isiklikud juurkasutaja reeglid</string>
|
||||
<string name="multiuser_hint_owner_request">Taotlus on saadetud seadme omanikule. Palun lülitu omanikule ja anna vajalikud load</string>
|
||||
|
||||
<string name="mount_namespace_mode">Nimeruumi monteerimisrežiim</string>
|
||||
<string name="settings_ns_global">Globaalne nimeruum</string>
|
||||
<string name="settings_ns_requester">Võta nimeruum üle</string>
|
||||
<string name="settings_ns_isolate">Isoleeritud nimeruum</string>
|
||||
<string name="global_summary">Kõik juurkasutaja sessioonid kasutavad globaalset monteerimise nimeruumi</string>
|
||||
<string name="requester_summary">Juurkasutaja sessioonid võtavad üle selle taotleja nimeruumi</string>
|
||||
<string name="isolate_summary">Iga juurkasutaja sessioon saab oma isoleeritud nimeruumi</string>
|
||||
<string name="android_o_not_support">Pole toetatud Androidi versioonis 8.0+</string>
|
||||
<string name="disable_fingerprint">Sõrmejälgi pole määratud või seade pole toetatud</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Superkasutaja taotlus</string>
|
||||
<string name="deny_with_str">Keela %1$s</string>
|
||||
<string name="deny">Keela</string>
|
||||
<string name="prompt">Küsi</string>
|
||||
<string name="grant">Luba</string>
|
||||
<string name="su_warning">Annab täieliku ligipääsu sinu seadmele.\nKeela, kui sa pole kindel!</string>
|
||||
<string name="forever">Igavesti</string>
|
||||
<string name="once">Üks kord</string>
|
||||
<string name="tenmin">10 min</string>
|
||||
<string name="twentymin">20 min</string>
|
||||
<string name="thirtymin">30 min</string>
|
||||
<string name="sixtymin">60 min</string>
|
||||
<string name="su_allow_toast">Rakendusele %1$s anti superkasutaja õigused</string>
|
||||
<string name="su_deny_toast">Rakendusel %1$s keelati superkasutaja õigused</string>
|
||||
<string name="no_apps_found">Rakendusi ei leitud</string>
|
||||
<string name="su_snack_grant">Superkasutaja õigused antud rakendusele %1$s</string>
|
||||
<string name="su_snack_deny">Superkasutaja õigused keelatud rakendusele %1$s</string>
|
||||
<string name="su_snack_notif_on">Teated lubatud rakendusele %1$s</string>
|
||||
<string name="su_snack_notif_off">Teated keelatud rakendusele %1$s</string>
|
||||
<string name="su_snack_log_on">Logimine lubatud rakendusele %1$s</string>
|
||||
<string name="su_snack_log_off">Logimine keelatud rakendusele %1$s</string>
|
||||
<string name="su_snack_revoke">Rakenduse %1$s õigused on eemaldatud</string>
|
||||
<string name="su_revoke_title">Eemaldad?</string>
|
||||
<string name="su_revoke_msg">Kinnitad rakenduse %1$s õiguste eemaldamise?</string>
|
||||
<string name="toast">Hüpik</string>
|
||||
<string name="none">Puudub</string>
|
||||
<string name="auth_fail">Autentimine ebaõnnestus</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID:\\u0020</string>
|
||||
<string name="target_uid">Siht-UID:\\u0020</string>
|
||||
<string name="command">Käsklus:\\u0020</string>
|
||||
|
||||
</resources>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user