mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 17:27:24 +00:00
Compare commits
711 Commits
v26.0
...
canary-270
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0495468d02 | ||
![]() |
300a2a242c | ||
![]() |
33aebb5976 | ||
![]() |
b3d6809c0b | ||
![]() |
461f7e9f89 | ||
![]() |
9cc50b20d8 | ||
![]() |
f488e9df8f | ||
![]() |
0dc596e206 | ||
![]() |
c3bf03190b | ||
![]() |
021ae891a9 | ||
![]() |
9c03514eb1 | ||
![]() |
eb74b266e1 | ||
![]() |
80eb6ff25a | ||
![]() |
7b81e2d2d1 | ||
![]() |
a8789073f1 | ||
![]() |
c8fe0f5524 | ||
![]() |
d33b077a13 | ||
![]() |
2282365cf8 | ||
![]() |
9a00b7b942 | ||
![]() |
d54baadbed | ||
![]() |
0869a90fe3 | ||
![]() |
2754b1dcf8 | ||
![]() |
0db6314661 | ||
![]() |
b5d2ef18e8 | ||
![]() |
6e22476acc | ||
![]() |
b26db8cee6 | ||
![]() |
33cb39c8af | ||
![]() |
f247759a6e | ||
![]() |
de7e5bdfe7 | ||
![]() |
53a8ba8cfe | ||
![]() |
f2d057baba | ||
![]() |
93bcf2cd25 | ||
![]() |
6d82515cfc | ||
![]() |
a177d3b022 | ||
![]() |
92b2e06e57 | ||
![]() |
f919bb0e99 | ||
![]() |
054971e899 | ||
![]() |
93c3d36452 | ||
![]() |
4c38af994d | ||
![]() |
bbb8efe92c | ||
![]() |
659dd09723 | ||
![]() |
4931825912 | ||
![]() |
ef81cdab4f | ||
![]() |
7c0b25cad9 | ||
![]() |
b38ab2a7d6 | ||
![]() |
a97191052b | ||
![]() |
2963d4ca9e | ||
![]() |
6aab856de7 | ||
![]() |
94d1c66f8a | ||
![]() |
7ff4d7608e | ||
![]() |
46ef915c83 | ||
![]() |
63b0a0d96b | ||
![]() |
ea4cabdfc5 | ||
![]() |
0185ddf577 | ||
![]() |
ddae568741 | ||
![]() |
fcb7ebb090 | ||
![]() |
8d446fcc16 | ||
![]() |
881d3b5221 | ||
![]() |
fe9ec3bc6d | ||
![]() |
480198dcd0 | ||
![]() |
4ab7bc0d97 | ||
![]() |
7173693d1b | ||
![]() |
6b81716440 | ||
![]() |
88e8e15607 | ||
![]() |
69181a6b72 | ||
![]() |
b11b81122a | ||
![]() |
648e3ee36b | ||
![]() |
724b94f320 | ||
![]() |
a6e65f9a7e | ||
![]() |
af5c4d09c4 | ||
![]() |
872394cb58 | ||
![]() |
fcbbe9a22e | ||
![]() |
b168163ef0 | ||
![]() |
3e38b8fed1 | ||
![]() |
f90c548f27 | ||
![]() |
c981c40218 | ||
![]() |
dcbf37c5e8 | ||
![]() |
300b233a27 | ||
![]() |
e32cd03d0b | ||
![]() |
a07b9315a5 | ||
![]() |
e9694c6195 | ||
![]() |
4a2a37c87a | ||
![]() |
7dca5b831a | ||
![]() |
be5ff68140 | ||
![]() |
59f40d5fe5 | ||
![]() |
1fbd053a42 | ||
![]() |
966c6314f8 | ||
![]() |
c92204c724 | ||
![]() |
bb9947d4d2 | ||
![]() |
7c8cdb4ad6 | ||
![]() |
bd7f9c9e46 | ||
![]() |
9a33a4dfe2 | ||
![]() |
47e918bc92 | ||
![]() |
c194168d9b | ||
![]() |
cacc60b1ac | ||
![]() |
52063b3652 | ||
![]() |
85a4eaff59 | ||
![]() |
45fa1fce70 | ||
![]() |
2112c916f5 | ||
![]() |
d6e159bff9 | ||
![]() |
2f710a564f | ||
![]() |
27cfc4945c | ||
![]() |
7cdada92c8 | ||
![]() |
8f1e57d4f9 | ||
![]() |
8178666b49 | ||
![]() |
313532dcaa | ||
![]() |
2f8f3dc266 | ||
![]() |
df6ada5ce3 | ||
![]() |
a89b9e6af1 | ||
![]() |
23ed275614 | ||
![]() |
cfd1e0cf22 | ||
![]() |
eb400f19b1 | ||
![]() |
19f15f16f6 | ||
![]() |
e158cfddfa | ||
![]() |
d0cf93a08d | ||
![]() |
08ad0e74dd | ||
![]() |
722374a024 | ||
![]() |
c6f0762510 | ||
![]() |
941a363c5a | ||
![]() |
2afcdc64a0 | ||
![]() |
3c66c4bbc5 | ||
![]() |
9f5cd5e1cc | ||
![]() |
a35f2bb73b | ||
![]() |
6cf00130f4 | ||
![]() |
6c27ba6b88 | ||
![]() |
dd3b9980e7 | ||
![]() |
02e189a029 | ||
![]() |
72b8d12ee4 | ||
![]() |
eed03080c1 | ||
![]() |
090cb4b0f9 | ||
![]() |
6f2c76b898 | ||
![]() |
f61827cbec | ||
![]() |
3f2264f2c7 | ||
![]() |
c1cadf4bdc | ||
![]() |
0e56991369 | ||
![]() |
4dc1c59040 | ||
![]() |
33b7b8b297 | ||
![]() |
e6af5ed460 | ||
![]() |
b678afa4b6 | ||
![]() |
4bac2df4e7 | ||
![]() |
50416eee09 | ||
![]() |
73cf501d33 | ||
![]() |
d2b7907bed | ||
![]() |
99d5dd5ea8 | ||
![]() |
5fdb841fa8 | ||
![]() |
7c88484d64 | ||
![]() |
b22b6a4204 | ||
![]() |
2a3d34c812 | ||
![]() |
c50ee722a1 | ||
![]() |
ffc1e38e48 | ||
![]() |
6219d5fcbf | ||
![]() |
2e4440b702 | ||
![]() |
0d9ec0931b | ||
![]() |
60e8415369 | ||
![]() |
652a26d5d9 | ||
![]() |
f57839379a | ||
![]() |
36bd00a046 | ||
![]() |
fb5ee86615 | ||
![]() |
30bf5c8448 | ||
![]() |
2051836a73 | ||
![]() |
2cb0af1ff3 | ||
![]() |
a1b6568226 | ||
![]() |
1eddbfd72c | ||
![]() |
21ed095601 | ||
![]() |
000a2e4d59 | ||
![]() |
7abe635de9 | ||
![]() |
9a008c17ba | ||
![]() |
08dbf728a4 | ||
![]() |
4670f762d3 | ||
![]() |
efa49567fa | ||
![]() |
0ffc4527a7 | ||
![]() |
dd9d43be96 | ||
![]() |
865fca71a5 | ||
![]() |
6b4baa3bcd | ||
![]() |
a9ee2d7d18 | ||
![]() |
d654b9cb97 | ||
![]() |
4d2921e742 | ||
![]() |
ecc74d45d1 | ||
![]() |
5de597f079 | ||
![]() |
156b0e67ca | ||
![]() |
10069215f4 | ||
![]() |
92b305a389 | ||
![]() |
d20b30c771 | ||
![]() |
83209b21ff | ||
![]() |
81658d45f7 | ||
![]() |
c951b208a1 | ||
![]() |
050a073771 | ||
![]() |
21d374214f | ||
![]() |
19ea25a9d0 | ||
![]() |
dbf6e40dfe | ||
![]() |
d56f4fbc90 | ||
![]() |
73c3d741a7 | ||
![]() |
2b5fc75127 | ||
![]() |
991802ab82 | ||
![]() |
7f6b5305ba | ||
![]() |
825c6c4316 | ||
![]() |
f00408c793 | ||
![]() |
a6ff3672af | ||
![]() |
2290ddeb89 | ||
![]() |
74af79ad03 | ||
![]() |
b6c24a3a8a | ||
![]() |
a8c2ae223a | ||
![]() |
953d44302c | ||
![]() |
24e46a5971 | ||
![]() |
b1297c4192 | ||
![]() |
9ae328fd84 | ||
![]() |
625a1d6f44 | ||
![]() |
987e5f5413 | ||
![]() |
715284b70d | ||
![]() |
62fc7868ac | ||
![]() |
1a70796339 | ||
![]() |
af6965eefa | ||
![]() |
8f7d2e38f7 | ||
![]() |
be433fa667 | ||
![]() |
0ccd6e7381 | ||
![]() |
907bbbda41 | ||
![]() |
4393bc077d | ||
![]() |
365b373480 | ||
![]() |
47e6dd286d | ||
![]() |
0dbaf52566 | ||
![]() |
66f49dfab5 | ||
![]() |
f8967e9274 | ||
![]() |
a4f008fde5 | ||
![]() |
e9980c778b | ||
![]() |
06b6fb0c33 | ||
![]() |
38cb3d4105 | ||
![]() |
db99caf258 | ||
![]() |
39dbffadfe | ||
![]() |
b7505c3c9c | ||
![]() |
3185e5a7ca | ||
![]() |
e0cbe28711 | ||
![]() |
66cee19cea | ||
![]() |
2ec29ade79 | ||
![]() |
c865d4e187 | ||
![]() |
a42a0a53ce | ||
![]() |
6d79de7d71 | ||
![]() |
7e9abe6e90 | ||
![]() |
4d5510be4f | ||
![]() |
b04e1394c0 | ||
![]() |
2aa923191e | ||
![]() |
4bf1c74164 | ||
![]() |
472c7878b2 | ||
![]() |
38ad871e33 | ||
![]() |
c5d34670c4 | ||
![]() |
154121f3dd | ||
![]() |
3d91a561fe | ||
![]() |
2c6adbc69b | ||
![]() |
5280982363 | ||
![]() |
18c45ae289 | ||
![]() |
41fbd2a7be | ||
![]() |
5e45884af4 | ||
![]() |
d78ee171bc | ||
![]() |
356ee1febd | ||
![]() |
cc044ccc4c | ||
![]() |
9c638cc463 | ||
![]() |
df786eb2b6 | ||
![]() |
8e7186eebb | ||
![]() |
74b7b84561 | ||
![]() |
308c9999fa | ||
![]() |
930bb8687f | ||
![]() |
f2c4288d2d | ||
![]() |
b44141ae39 | ||
![]() |
86e0020964 | ||
![]() |
94d3daeadf | ||
![]() |
79334b7702 | ||
![]() |
df66458db6 | ||
![]() |
97705704e2 | ||
![]() |
1206179580 | ||
![]() |
a0b8aa4da6 | ||
![]() |
65207f96c8 | ||
![]() |
062e498bdd | ||
![]() |
1057cb3e3c | ||
![]() |
2dd23b2518 | ||
![]() |
8cab12998c | ||
![]() |
48b1c26dc8 | ||
![]() |
f1e0bc3e4a | ||
![]() |
38527cd58f | ||
![]() |
e94d65b4b2 | ||
![]() |
27ece3c7df | ||
![]() |
06687abffc | ||
![]() |
deedb462a0 | ||
![]() |
c48962bdf7 | ||
![]() |
1ef3f6e13b | ||
![]() |
83a34a9004 | ||
![]() |
e30bda6c8d | ||
![]() |
00e9d76a5a | ||
![]() |
6cda6c2fae | ||
![]() |
6dfda6dc39 | ||
![]() |
f41994cb52 | ||
![]() |
a003336497 | ||
![]() |
401090d6fe | ||
![]() |
90dcc1cd30 | ||
![]() |
2ac464b186 | ||
![]() |
8b7fae278b | ||
![]() |
d73c2daf6d | ||
![]() |
ca25935de3 | ||
![]() |
d7750b7220 | ||
![]() |
98861f0b5a | ||
![]() |
e35925d520 | ||
![]() |
685a2d2101 | ||
![]() |
f7e471616d | ||
![]() |
c013a349af | ||
![]() |
61ea59a27b | ||
![]() |
e55f338367 | ||
![]() |
1425cf4105 | ||
![]() |
b493a985b0 | ||
![]() |
1fe9ede940 | ||
![]() |
1fd49e4987 | ||
![]() |
d49b02b274 | ||
![]() |
d47e70cfaa | ||
![]() |
40cb031af5 | ||
![]() |
1dcf325547 | ||
![]() |
4e99997013 | ||
![]() |
334554697d | ||
![]() |
e77cbd0c15 | ||
![]() |
46ba008b9d | ||
![]() |
58aded31c2 | ||
![]() |
6f6b0ade06 | ||
![]() |
d9b67a207b | ||
![]() |
c7083659aa | ||
![]() |
a6d1803105 | ||
![]() |
66eef75673 | ||
![]() |
367f5f7b44 | ||
![]() |
0edcb03c45 | ||
![]() |
63eef153de | ||
![]() |
68442f38ac | ||
![]() |
8d5b9e5329 | ||
![]() |
6c0966b795 | ||
![]() |
7c2e93d266 | ||
![]() |
1ff7b9055f | ||
![]() |
49f241b77c | ||
![]() |
cfb20b0f86 | ||
![]() |
6d6f14fcb3 | ||
![]() |
977c981265 | ||
![]() |
ef48abf19d | ||
![]() |
65c18f9c09 | ||
![]() |
ecb31eed40 | ||
![]() |
a80cadf587 | ||
![]() |
fce1bf2365 | ||
![]() |
cbc6d40b2c | ||
![]() |
9fbd079560 | ||
![]() |
42eb928054 | ||
![]() |
577483fde1 | ||
![]() |
aa6c7c15cc | ||
![]() |
6c807d35b2 | ||
![]() |
8ca8cdae97 | ||
![]() |
75e37be6f3 | ||
![]() |
4985314ca6 | ||
![]() |
ac5ceb18c8 | ||
![]() |
72b39594d3 | ||
![]() |
16ae4aedf1 | ||
![]() |
3ba00858e6 | ||
![]() |
489100c755 | ||
![]() |
da766f2a4e | ||
![]() |
c81d7ff76c | ||
![]() |
a6e50d3648 | ||
![]() |
a177846044 | ||
![]() |
19a4e11645 | ||
![]() |
67cc36268e | ||
![]() |
28770b9a32 | ||
![]() |
9f92e1bf15 | ||
![]() |
23fe5d5a19 | ||
![]() |
9088b584f6 | ||
![]() |
beaf636415 | ||
![]() |
09bb2fe8dc | ||
![]() |
1d6747d90e | ||
![]() |
efadd94de3 | ||
![]() |
8c0b4e444a | ||
![]() |
32c7106e40 | ||
![]() |
d2f2a9e4c8 | ||
![]() |
985454afd4 | ||
![]() |
9e1322de25 | ||
![]() |
4e4ec73d94 | ||
![]() |
bb39a524d0 | ||
![]() |
196d9af099 | ||
![]() |
1eeb2a34a1 | ||
![]() |
cf43c56218 | ||
![]() |
e6c1aec443 | ||
![]() |
43fd1c4c1b | ||
![]() |
022caca979 | ||
![]() |
0352ea2cca | ||
![]() |
e483d6befe | ||
![]() |
678c07fff5 | ||
![]() |
91c92051f1 | ||
![]() |
4b8a0388e7 | ||
![]() |
66788dc58c | ||
![]() |
dd8c28b1cb | ||
![]() |
32c5153e8e | ||
![]() |
36de62873a | ||
![]() |
51e37880c6 | ||
![]() |
4b83c1e76c | ||
![]() |
b0b04690d5 | ||
![]() |
6d1e8d86cb | ||
![]() |
eda8c70a80 | ||
![]() |
587b6cfd41 | ||
![]() |
e774408782 | ||
![]() |
187f583c95 | ||
![]() |
f5d3a71478 | ||
![]() |
d868ff3080 | ||
![]() |
f80198a669 | ||
![]() |
6076b52c48 | ||
![]() |
79a1c39b30 | ||
![]() |
5c92d39498 | ||
![]() |
6e7a995716 | ||
![]() |
a55d570213 | ||
![]() |
5d07d0b964 | ||
![]() |
ec115cd7e3 | ||
![]() |
9b3896fd3d | ||
![]() |
a3f5918d25 | ||
![]() |
b28326198c | ||
![]() |
46275b90c2 | ||
![]() |
15e13a8d8b | ||
![]() |
b750c89c87 | ||
![]() |
8d7c7c3dfb | ||
![]() |
8e1a91509c | ||
![]() |
927cd571f8 | ||
![]() |
5fbd3e5c65 | ||
![]() |
877aeb66cb | ||
![]() |
8a88d8465a | ||
![]() |
dda8cc85c9 | ||
![]() |
6a59939d9a | ||
![]() |
4745e86c1b | ||
![]() |
9aa466c773 | ||
![]() |
0243610c09 | ||
![]() |
0a2a590ab7 | ||
![]() |
89aee6ffa7 | ||
![]() |
4eaf701cb7 | ||
![]() |
4fff2aa7d8 | ||
![]() |
35b3c8ba5c | ||
![]() |
1d7cff7703 | ||
![]() |
8d81bd0e33 | ||
![]() |
7826d7527f | ||
![]() |
d4e552d08b | ||
![]() |
5a16418543 | ||
![]() |
7297aba15a | ||
![]() |
bc5d5f9502 | ||
![]() |
1761986c1b | ||
![]() |
1e034e3e0e | ||
![]() |
bbf9756bfa | ||
![]() |
96e559fb0e | ||
![]() |
4c45775131 | ||
![]() |
c072b4254d | ||
![]() |
2dbb812126 | ||
![]() |
be50f17f55 | ||
![]() |
6f77f190f2 | ||
![]() |
6bdc57cbe4 | ||
![]() |
de00f1d5a9 | ||
![]() |
e9b9bf987b | ||
![]() |
f4b6385f9f | ||
![]() |
75d905a56d | ||
![]() |
b1363ee479 | ||
![]() |
51afe43a30 | ||
![]() |
189c03c047 | ||
![]() |
ae9d270a32 | ||
![]() |
e47e869f6b | ||
![]() |
c39038a439 | ||
![]() |
69174e2c13 | ||
![]() |
474268a0af | ||
![]() |
eadb0307fa | ||
![]() |
5a5d0d5d72 | ||
![]() |
a1273bc467 | ||
![]() |
0c28a916be | ||
![]() |
0ba573b789 | ||
![]() |
ec42ee152c | ||
![]() |
abcb487361 | ||
![]() |
d12d9e82f1 | ||
![]() |
275208e81b | ||
![]() |
41226c12b8 | ||
![]() |
f86c66c99d | ||
![]() |
93876b5fd3 | ||
![]() |
b5b14ce343 | ||
![]() |
350d0d600c | ||
![]() |
f924ffcbf3 | ||
![]() |
0f5963f231 | ||
![]() |
1961ff2c40 | ||
![]() |
40003691d6 | ||
![]() |
8290358241 | ||
![]() |
ee34f775c3 | ||
![]() |
feb47cd88c | ||
![]() |
c6efb51f61 | ||
![]() |
a5acf33ccd | ||
![]() |
ab9ee449e4 | ||
![]() |
9571b6f9be | ||
![]() |
207d7fd3f6 | ||
![]() |
bcdcfa1104 | ||
![]() |
e0a4230dac | ||
![]() |
17ba5cba3e | ||
![]() |
f2e109ad7d | ||
![]() |
c83e141a1c | ||
![]() |
6089cc36de | ||
![]() |
9638dc0a66 | ||
![]() |
b191a14a23 | ||
![]() |
cf1bc82537 | ||
![]() |
6141bb5bb3 | ||
![]() |
4d2b62da0d | ||
![]() |
39383229d1 | ||
![]() |
08bfbb154a | ||
![]() |
d390ca2fdf | ||
![]() |
7ad77a14ae | ||
![]() |
f33343b4e6 | ||
![]() |
af65d07456 | ||
![]() |
16d728f379 | ||
![]() |
c97ab690b6 | ||
![]() |
4caed73fe0 | ||
![]() |
4856da1584 | ||
![]() |
0a07018fec | ||
![]() |
64c82e1f2c | ||
![]() |
e8e8afa6c2 | ||
![]() |
af2207433d | ||
![]() |
75ba62d588 | ||
![]() |
606d97ae4d | ||
![]() |
d778b0b0a7 | ||
![]() |
5ee6daf126 | ||
![]() |
43b9a09c9b | ||
![]() |
8475a2bb94 | ||
![]() |
d8692de2f4 | ||
![]() |
33a9abc946 | ||
![]() |
ee943afbc9 | ||
![]() |
1f7c3e9f14 | ||
![]() |
46770db18b | ||
![]() |
92f980601c | ||
![]() |
d0b8c16651 | ||
![]() |
a470ee6f93 | ||
![]() |
ff1c56683d | ||
![]() |
4ee4cbada6 | ||
![]() |
dbc2236dd2 | ||
![]() |
a8c4a33e91 | ||
![]() |
279f955a84 | ||
![]() |
fbd1dbb20c | ||
![]() |
6c09fc2e64 | ||
![]() |
f3304b482c | ||
![]() |
0a85ef61c3 | ||
![]() |
dc26ad7125 | ||
![]() |
24b1c607f3 | ||
![]() |
732a161b67 | ||
![]() |
9c7cf340a1 | ||
![]() |
399b9e5eba | ||
![]() |
5805573625 | ||
![]() |
a6b1149b9f | ||
![]() |
51e985ae7f | ||
![]() |
9929b25339 | ||
![]() |
2359cfc480 | ||
![]() |
81493475f9 | ||
![]() |
0493829231 | ||
![]() |
e2d1952ad9 | ||
![]() |
7450965458 | ||
![]() |
f45384685b | ||
![]() |
8abcccc262 | ||
![]() |
a9c89cbbbb | ||
![]() |
d2eaa6e6c1 | ||
![]() |
53257b6ea1 | ||
![]() |
c874391be4 | ||
![]() |
7e8e013832 | ||
![]() |
037f46f7f0 | ||
![]() |
d3e1c496ca | ||
![]() |
d7d0a44693 | ||
![]() |
9d6f6764cb | ||
![]() |
cb3ab63815 | ||
![]() |
caae932117 | ||
![]() |
e9cf27eb5a | ||
![]() |
6ee6685f4c | ||
![]() |
d15017b777 | ||
![]() |
a9387e63e1 | ||
![]() |
23c1f0111b | ||
![]() |
866386e21f | ||
![]() |
bf10496fa9 | ||
![]() |
607e6547a7 | ||
![]() |
6b21091fe2 | ||
![]() |
e58f98e844 | ||
![]() |
b8cb9cd84d | ||
![]() |
c1038ac6f9 | ||
![]() |
c556dd0aac | ||
![]() |
d2fbcd07b7 | ||
![]() |
bf6359abaa | ||
![]() |
d1621845b8 | ||
![]() |
f33f1d25d0 | ||
![]() |
40f25f4d56 | ||
![]() |
e13775ec2c | ||
![]() |
ee4dad7a13 | ||
![]() |
5e2ef1b7f4 | ||
![]() |
f8c38eab74 | ||
![]() |
305e8b3d14 | ||
![]() |
2a654e5d7f | ||
![]() |
57afae3425 | ||
![]() |
feb44f875e | ||
![]() |
7eebe62bb6 | ||
![]() |
9ea9f01933 | ||
![]() |
665c6bdc4b | ||
![]() |
c79bc83275 | ||
![]() |
c30fbdf145 | ||
![]() |
f12951bd1d | ||
![]() |
52f2e8c4a0 | ||
![]() |
1b2af1ed6d | ||
![]() |
0f9b2a7df8 | ||
![]() |
f2846694e1 | ||
![]() |
e668dbf6f7 | ||
![]() |
d77a368176 | ||
![]() |
ad0da08610 | ||
![]() |
0c52385ad4 | ||
![]() |
5b8b48ccc1 | ||
![]() |
659b9c6fee | ||
![]() |
ec31cab5a7 | ||
![]() |
dd93556ad8 | ||
![]() |
533aeadd38 | ||
![]() |
18d0cedbe2 | ||
![]() |
5a94ef9106 | ||
![]() |
8e8f01f8b5 | ||
![]() |
7087badf87 | ||
![]() |
47d2d4e3a5 | ||
![]() |
6c47d8f556 | ||
![]() |
8c9d0314fb | ||
![]() |
69144942e3 | ||
![]() |
5627053b74 | ||
![]() |
0f666de5e6 | ||
![]() |
eddc862fa3 | ||
![]() |
4327682120 | ||
![]() |
af5bdee78f | ||
![]() |
0e36e86dbf | ||
![]() |
f95478f1f1 | ||
![]() |
9fe8741a02 | ||
![]() |
a5768e02ea | ||
![]() |
f5aaff2b1e | ||
![]() |
655f778171 | ||
![]() |
2e77a426b2 | ||
![]() |
2bcf2e76f1 | ||
![]() |
57bd450798 | ||
![]() |
582cad1b8d | ||
![]() |
6ca2a3d841 | ||
![]() |
91773c3311 | ||
![]() |
dc61033b2c | ||
![]() |
f8d62a4b6c | ||
![]() |
1d2145b1b7 | ||
![]() |
1f7f84b74a | ||
![]() |
cd7a335d0f | ||
![]() |
17569005a4 | ||
![]() |
f36b21bae5 | ||
![]() |
fe1ca52f6d | ||
![]() |
1be647a279 | ||
![]() |
2ea1a47bec | ||
![]() |
2d799dae0d | ||
![]() |
c6408babac | ||
![]() |
a8c1ed8795 | ||
![]() |
e3cb5f8ddd | ||
![]() |
e160e211dd | ||
![]() |
22d05ca399 | ||
![]() |
bd2651057d | ||
![]() |
1610092ec4 | ||
![]() |
b9e6937996 | ||
![]() |
a207f03952 | ||
![]() |
851153dd7c | ||
![]() |
583ffc8177 | ||
![]() |
7518092ad2 | ||
![]() |
8c2ad3883a | ||
![]() |
d364554425 | ||
![]() |
726ffdcd98 | ||
![]() |
f9d22cf8ee | ||
![]() |
ee50da566f | ||
![]() |
9f7d410959 | ||
![]() |
bc94ea4334 | ||
![]() |
c0c9204848 | ||
![]() |
c0d1bf63bc | ||
![]() |
bbda0cdffe | ||
![]() |
7b5ff99cd1 | ||
![]() |
21ddb26db8 | ||
![]() |
7bf2e3875f | ||
![]() |
b136aba1e2 | ||
![]() |
0d84f80b3c | ||
![]() |
af45aeb771 | ||
![]() |
1c5a435e1f | ||
![]() |
0ea1257dcd | ||
![]() |
4c92677b5a | ||
![]() |
979260bd62 | ||
![]() |
f7de649a36 | ||
![]() |
0cf0d2b821 | ||
![]() |
3733c9a091 | ||
![]() |
e9f32e4f68 | ||
![]() |
68c2817d40 | ||
![]() |
83d837d868 | ||
![]() |
093eb15ee1 | ||
![]() |
c6412c1b1b | ||
![]() |
1151393d74 | ||
![]() |
468f3efb13 | ||
![]() |
d6b19b9d4c | ||
![]() |
709f25f600 | ||
![]() |
4b16e4b026 | ||
![]() |
cdfbc02922 | ||
![]() |
d0c9384233 | ||
![]() |
2488668b06 | ||
![]() |
52a98cbd51 | ||
![]() |
1840c4c486 | ||
![]() |
34080f3958 | ||
![]() |
e9b76b6aa5 | ||
![]() |
b7799b53d9 | ||
![]() |
1e206515c7 | ||
![]() |
6bb313184d | ||
![]() |
2763992434 | ||
![]() |
18fe0e6442 | ||
![]() |
a70c73bffd | ||
![]() |
b4ae3493a6 | ||
![]() |
1a16004b20 | ||
![]() |
56707b8119 | ||
![]() |
c3f9533ddc | ||
![]() |
3b3abd63cc | ||
![]() |
411d3ed4e9 | ||
![]() |
f29cc26103 | ||
![]() |
1cd595a598 | ||
![]() |
22e023b58d | ||
![]() |
7be958e35d | ||
![]() |
69b66ef637 | ||
![]() |
daf8653c38 | ||
![]() |
e2545e57cf |
44
.github/actions/setup/action.yml
vendored
Normal file
44
.github/actions/setup/action.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Magisk Setup
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "17"
|
||||
|
||||
- name: Set up Python 3
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
- name: Set up sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ runner.os }}-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}
|
||||
max-size: 10000M
|
||||
|
||||
- name: Cache Gradle dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
!~/.gradle/caches/build-cache-*
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle-
|
||||
|
||||
- name: Cache build cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches/build-cache-*
|
||||
key: ${{ runner.os }}-build-cache-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}-build-cache-
|
||||
|
||||
- name: Set up NDK
|
||||
run: python build.py -v ndk
|
||||
shell: bash
|
241
.github/workflows/build.yml
vendored
241
.github/workflows/build.yml
vendored
@@ -2,107 +2,194 @@ name: Magisk Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches: [master]
|
||||
paths:
|
||||
- 'app/**'
|
||||
- 'native/**'
|
||||
- 'stub/**'
|
||||
- 'buildSrc/**'
|
||||
- 'build.py'
|
||||
- 'gradle.properties'
|
||||
- '.github/workflows/build.yml'
|
||||
- "app/**"
|
||||
- "native/**"
|
||||
- "buildSrc/**"
|
||||
- "build.py"
|
||||
- "gradle.properties"
|
||||
- ".github/workflows/build.yml"
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Build Magisk artifacts
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SCCACHE_DIRECT: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
env:
|
||||
NDK_CCACHE: ccache
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_COMPILERCHECK: "%compiler% -dumpmachine; %compiler% -dumpversion"
|
||||
RUSTC_WRAPPER: sccache
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
submodules: "recursive"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: Set up Python 3
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Set up ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}
|
||||
|
||||
- name: Set up sccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
variant: sccache
|
||||
key: ${{ runner.os }}-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}
|
||||
|
||||
- name: Cache Gradle dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
!~/.gradle/caches/build-cache-*
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}
|
||||
restore-keys: ${{ runner.os }}-gradle-
|
||||
|
||||
- name: Cache build cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches/build-cache-*
|
||||
key: ${{ runner.os }}-build-cache-${{ github.sha }}
|
||||
restore-keys: ${{ runner.os }}-build-cache-
|
||||
|
||||
- name: Set up NDK
|
||||
run: python build.py -v ndk
|
||||
- name: Setup environment
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
- name: Build release
|
||||
run: |
|
||||
python build.py -vr all
|
||||
run: ./build.py -vr all
|
||||
|
||||
- name: Build debug
|
||||
run: |
|
||||
python build.py -v all
|
||||
run: ./build.py -v all
|
||||
|
||||
- name: Stop gradle daemon
|
||||
run: ./gradlew --stop
|
||||
|
||||
# Only upload artifacts built on Linux
|
||||
- name: Upload build artifact
|
||||
if: runner.os == 'Linux'
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.sha }}
|
||||
path: out
|
||||
compression-level: 9
|
||||
|
||||
- name: Upload mapping and native debug symbols
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.sha }}-symbols
|
||||
path: app/apk/build/outputs
|
||||
compression-level: 9
|
||||
|
||||
test-build:
|
||||
name: Test building on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
SCCACHE_DIRECT: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest, macos-14]
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: "recursive"
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup environment
|
||||
uses: ./.github/actions/setup
|
||||
|
||||
- name: Build debug
|
||||
run: python build.py -v all
|
||||
|
||||
- name: Stop gradle daemon
|
||||
run: ./gradlew --stop
|
||||
|
||||
avd-test:
|
||||
name: Test API ${{ matrix.version }} (x86_64)
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]
|
||||
type: [""]
|
||||
include:
|
||||
- version: 35
|
||||
type: "google_apis"
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ github.sha }}
|
||||
path: out
|
||||
|
||||
- name: Upload mapping and native debug symbols
|
||||
if: runner.os == 'Linux'
|
||||
uses: actions/upload-artifact@v3
|
||||
- name: Enable KVM group perms
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: Run AVD test
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
AVD_TEST_VERBOSE: 1
|
||||
run: scripts/avd_test.sh ${{ matrix.version }} ${{ matrix.type }}
|
||||
|
||||
avd-test-32:
|
||||
name: Test API ${{ matrix.version }} (x86)
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
version: [23, 24, 25, 26, 27, 28, 29, 30]
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
name: ${{ github.sha }}-symbols
|
||||
path: app/build/outputs
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ github.sha }}
|
||||
path: out
|
||||
|
||||
- name: Enable KVM group perms
|
||||
run: |
|
||||
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: Run AVD test
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
FORCE_32_BIT: 1
|
||||
AVD_TEST_VERBOSE: 1
|
||||
run: scripts/avd_test.sh ${{ matrix.version }}
|
||||
|
||||
cf_test:
|
||||
name: Test ${{ matrix.branch }} (${{ matrix.target }})
|
||||
runs-on: ubuntu-24.04
|
||||
needs: build
|
||||
env:
|
||||
CF_HOME: /home/runner/aosp_cf_phone
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- branch: "aosp-main"
|
||||
target: "aosp_cf_x86_64_phone-trunk_staging-userdebug"
|
||||
|
||||
steps:
|
||||
- name: Check out
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ github.sha }}
|
||||
path: out
|
||||
|
||||
- name: Setup Cuttlefish environment
|
||||
run: |
|
||||
scripts/cuttlefish.sh setup
|
||||
scripts/cuttlefish.sh download ${{ matrix.branch }} ${{ matrix.target }}
|
||||
|
||||
- name: Run Cuttlefish test
|
||||
timeout-minutes: 10
|
||||
run: su $USER -c 'scripts/cuttlefish.sh test'
|
||||
|
||||
- name: Upload logs on error
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: "cvd-logs"
|
||||
path: |
|
||||
/home/runner/aosp_cf_phone/cuttlefish/instances/cvd-1/logs
|
||||
/home/runner/aosp_cf_phone/cuttlefish/instances/cvd-1/cuttlefish_config.json
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,8 +3,9 @@ out
|
||||
*.jks
|
||||
*.apk
|
||||
/config.prop
|
||||
/notes.md
|
||||
/update.sh
|
||||
/dict.txt
|
||||
/app/dict.txt
|
||||
|
||||
# Built binaries
|
||||
native/out
|
||||
|
24
.gitmodules
vendored
24
.gitmodules
vendored
@@ -1,12 +1,6 @@
|
||||
[submodule "selinux"]
|
||||
path = native/src/external/selinux
|
||||
url = https://github.com/topjohnwu/selinux.git
|
||||
[submodule "busybox"]
|
||||
path = native/src/external/busybox
|
||||
url = https://github.com/topjohnwu/ndk-busybox.git
|
||||
[submodule "dtc"]
|
||||
path = native/src/external/dtc
|
||||
url = https://github.com/dgibson/dtc.git
|
||||
[submodule "lz4"]
|
||||
path = native/src/external/lz4
|
||||
url = https://github.com/lz4/lz4.git
|
||||
@@ -16,24 +10,12 @@
|
||||
[submodule "xz"]
|
||||
path = native/src/external/xz
|
||||
url = https://github.com/xz-mirror/xz.git
|
||||
[submodule "nanopb"]
|
||||
path = native/src/external/nanopb
|
||||
url = https://github.com/nanopb/nanopb.git
|
||||
[submodule "mincrypt"]
|
||||
path = native/src/external/mincrypt
|
||||
url = https://github.com/topjohnwu/mincrypt.git
|
||||
[submodule "pcre"]
|
||||
path = native/src/external/pcre
|
||||
url = https://android.googlesource.com/platform/external/pcre
|
||||
[submodule "libcxx"]
|
||||
path = native/src/external/libcxx
|
||||
url = https://github.com/topjohnwu/libcxx.git
|
||||
[submodule "zlib"]
|
||||
path = native/src/external/zlib
|
||||
url = https://android.googlesource.com/platform/external/zlib
|
||||
[submodule "parallel-hashmap"]
|
||||
path = native/src/external/parallel-hashmap
|
||||
url = https://github.com/greg7mdp/parallel-hashmap.git
|
||||
[submodule "zopfli"]
|
||||
path = native/src/external/zopfli
|
||||
url = https://github.com/google/zopfli.git
|
||||
@@ -43,6 +25,12 @@
|
||||
[submodule "lsplt"]
|
||||
path = native/src/external/lsplt
|
||||
url = https://github.com/LSPosed/LSPlt.git
|
||||
[submodule "system_properties"]
|
||||
path = native/src/external/system_properties
|
||||
url = https://github.com/topjohnwu/system_properties.git
|
||||
[submodule "crt0"]
|
||||
path = native/src/external/crt0
|
||||
url = https://github.com/topjohnwu/crt0.git
|
||||
[submodule "termux-elf-cleaner"]
|
||||
path = tools/termux-elf-cleaner
|
||||
url = https://github.com/termux/termux-elf-cleaner.git
|
||||
|
39
README.MD
39
README.MD
@@ -18,15 +18,18 @@ Some highlight features:
|
||||
|
||||
[Github](https://github.com/topjohnwu/Magisk/) is the only source where you can get official Magisk information and downloads.
|
||||
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v25.2)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v25.2)
|
||||
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-release.apk)
|
||||
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-debug.apk)
|
||||
Click the icon below to download Magisk apk.
|
||||
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v27.0)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v27.0)
|
||||
[](https://github.com/topjohnwu/Magisk/releases/tag/canary-27006)
|
||||
|
||||
## Useful Links
|
||||
|
||||
- [Installation Instruction](https://topjohnwu.github.io/Magisk/install.html)
|
||||
- [Building and Development](https://topjohnwu.github.io/Magisk/build.html)
|
||||
- [Magisk Documentation](https://topjohnwu.github.io/Magisk/)
|
||||
- [Zygisk module sample](https://github.com/topjohnwu/zygisk-module-sample)
|
||||
|
||||
## Bug Reports
|
||||
|
||||
@@ -36,36 +39,12 @@ For installation issues, upload both boot image and install logs.<br>
|
||||
For Magisk issues, upload boot logcat or dmesg.<br>
|
||||
For Magisk app crashes, record and upload the logcat when the crash occurs.
|
||||
|
||||
## Building and Development
|
||||
|
||||
- Magisk builds on any OS Android Studio supports. Install Android Studio and do the initial setups.
|
||||
- Clone sources: `git clone --recurse-submodules https://github.com/topjohnwu/Magisk.git`
|
||||
- Install Python 3.8+ \
|
||||
(Windows only: select **'Add Python to PATH'** in installer, and run `pip install colorama` after install)
|
||||
- Configure to use the JDK bundled in Android Studio:
|
||||
- macOS: `export JAVA_HOME="/Applications/Android Studio.app/Contents/jre/Contents/Home"`
|
||||
- Linux: `export PATH="/path/to/androidstudio/jre/bin:$PATH"`
|
||||
- Windows: Add `C:\Path\To\Android Studio\jre\bin` to environment variable `PATH`
|
||||
- Set environment variable `ANDROID_SDK_ROOT` to the Android SDK folder (can be found in Android Studio settings)
|
||||
- Run `./build.py ndk` to let the script download and install NDK for you
|
||||
- To start building, run `build.py` to see your options. \
|
||||
For each action, use `-h` to access help (e.g. `./build.py all -h`)
|
||||
- To start development, open the project with Android Studio. The IDE can be used for both app (Kotlin/Java) and native sources.
|
||||
- Optionally, set custom configs with `config.prop`. A sample `config.prop.sample` is provided.
|
||||
|
||||
## Signing and Distribution
|
||||
|
||||
- The certificate of the key used to sign the final Magisk APK product is also directly embedded into some executables. In release builds, Magisk's root daemon will enforce this certificate check and reject and forcefully uninstall any non-matching Magisk apps to protect users from malicious and unverified Magisk APKs.
|
||||
- To do any development on Magisk itself, switch to an **official debug build and reinstall Magisk** to bypass the signature check.
|
||||
- To distribute your own Magisk builds signed with your own keys, set your signing configs in `config.prop`.
|
||||
- Check [Google's Documentation](https://developer.android.com/studio/publish/app-signing.html#generate-key) for more details on generating your own key.
|
||||
|
||||
## Translation Contributions
|
||||
|
||||
Default string resources for the Magisk app and its stub APK are located here:
|
||||
|
||||
- `app/src/main/res/values/strings.xml`
|
||||
- `stub/src/main/res/values/strings.xml`
|
||||
- `app/core/src/main/res/values/strings.xml`
|
||||
- `app/stub/src/main/res/values/strings.xml`
|
||||
|
||||
Translate each and place them in the respective locations (`[module]/src/main/res/values-[lang]/strings.xml`).
|
||||
|
||||
|
11
app/.gitignore
vendored
11
app/.gitignore
vendored
@@ -1,11 +0,0 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
.idea/
|
||||
/build
|
||||
*.hprof
|
||||
.externalNativeBuild/
|
||||
*.apk
|
||||
src/*/assets
|
||||
src/*/jniLibs
|
||||
src/*/resources
|
1
app/apk/.gitignore
vendored
Normal file
1
app/apk/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
69
app/apk/build.gradle.kts
Normal file
69
app/apk/build.gradle.kts
Normal file
@@ -0,0 +1,69 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
kotlin("android")
|
||||
kotlin("plugin.parcelize")
|
||||
kotlin("kapt")
|
||||
id("androidx.navigation.safeargs.kotlin")
|
||||
}
|
||||
|
||||
setupAppCommon()
|
||||
|
||||
kapt {
|
||||
correctErrorTypes = true
|
||||
useBuildCache = true
|
||||
mapDiagnosticLocations = true
|
||||
javacOptions {
|
||||
option("-Xmaxerrs", 1000)
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.topjohnwu.magisk"
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.topjohnwu.magisk"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
versionName = Config.version
|
||||
versionCode = Config.versionCode
|
||||
ndk {
|
||||
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64", "riscv64")
|
||||
debugSymbolLevel = "FULL"
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true
|
||||
proguardFiles("proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
dataBinding = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":app:core"))
|
||||
|
||||
implementation("com.github.topjohnwu:indeterminate-checkbox:1.0.7")
|
||||
implementation("dev.rikka.rikkax.layoutinflater:layoutinflater:1.3.0")
|
||||
implementation("dev.rikka.rikkax.insets:insets:1.3.0")
|
||||
implementation("dev.rikka.rikkax.recyclerview:recyclerview-ktx:1.3.2")
|
||||
|
||||
val vNav = "2.7.7"
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:${vNav}")
|
||||
implementation("androidx.navigation:navigation-ui-ktx:${vNav}")
|
||||
|
||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||
implementation("androidx.recyclerview:recyclerview:1.3.2")
|
||||
implementation("androidx.transition:transition:1.5.1")
|
||||
implementation("androidx.fragment:fragment-ktx:1.8.2")
|
||||
implementation("androidx.appcompat:appcompat:1.7.0")
|
||||
implementation("com.google.android.material:material:1.12.0")
|
||||
|
||||
// Make sure kapt runs with a proper kotlin-stdlib
|
||||
kapt(kotlin("stdlib"))
|
||||
}
|
33
app/apk/src/main/AndroidManifest.xml
Normal file
33
app/apk/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application android:localeConfig="@xml/locale_config">
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
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>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ui.surequest.SuRequestActivity"
|
||||
android:directBootAware="true"
|
||||
android:exported="false"
|
||||
android:taskAffinity=""
|
||||
tools:ignore="AppLinkUrlError">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@@ -10,9 +10,9 @@ import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.OnRebindCallback
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.navigation.NavDirections
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.ktx.startAnimations
|
||||
|
||||
abstract class BaseFragment<Binding : ViewDataBinding> : Fragment(), ViewModelHolder {
|
||||
|
||||
@@ -38,6 +38,9 @@ abstract class BaseFragment<Binding : ViewDataBinding> : Fragment(), ViewModelHo
|
||||
it.setVariable(BR.viewModel, viewModel)
|
||||
it.lifecycleOwner = viewLifecycleOwner
|
||||
}
|
||||
if (this is MenuProvider) {
|
||||
activity?.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.STARTED)
|
||||
}
|
||||
savedInstanceState?.let { viewModel.onRestoreState(it) }
|
||||
return binding.root
|
||||
}
|
||||
@@ -67,8 +70,6 @@ abstract class BaseFragment<Binding : ViewDataBinding> : Fragment(), ViewModelHo
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
if (this is MenuProvider)
|
||||
activity?.addMenuProvider(this, viewLifecycleOwner)
|
||||
binding.addOnRebindCallback(object : OnRebindCallback<Binding>() {
|
||||
override fun onPreBind(binding: Binding): Boolean {
|
||||
this@BaseFragment.onPreBind(binding)
|
||||
@@ -92,5 +93,4 @@ abstract class BaseFragment<Binding : ViewDataBinding> : Fragment(), ViewModelHo
|
||||
fun NavDirections.navigate() {
|
||||
navigation?.currentDestination?.getAction(actionId)?.let { navigation!!.navigate(this) }
|
||||
}
|
||||
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
package com.topjohnwu.magisk.arch
|
||||
|
||||
import android.Manifest.permission.*
|
||||
import android.Manifest.permission.POST_NOTIFICATIONS
|
||||
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
|
||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import androidx.databinding.PropertyChangeRegistry
|
||||
@@ -8,7 +10,7 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.navigation.NavDirections
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.databinding.ObservableHost
|
||||
import com.topjohnwu.magisk.events.BackPressEvent
|
||||
import com.topjohnwu.magisk.events.DialogBuilder
|
@@ -1,26 +1,39 @@
|
||||
package com.topjohnwu.magisk.arch
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.res.use
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||
import androidx.transition.AutoTransition
|
||||
import androidx.transition.TransitionManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.base.ActivityExtension
|
||||
import com.topjohnwu.magisk.core.base.IActivityExtension
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.ktx.reflectField
|
||||
import com.topjohnwu.magisk.core.wrap
|
||||
import rikka.insets.WindowInsetsHelper
|
||||
import rikka.layoutinflater.view.LayoutInflaterFactory
|
||||
|
||||
abstract class UIActivity<Binding : ViewDataBinding> : BaseActivity(), ViewModelHolder {
|
||||
abstract class UIActivity<Binding : ViewDataBinding>
|
||||
: AppCompatActivity(), ViewModelHolder, IActivityExtension {
|
||||
|
||||
protected lateinit var binding: Binding
|
||||
protected abstract val layoutRes: Int
|
||||
override val extension = ActivityExtension(this)
|
||||
|
||||
protected val binded get() = ::binding.isInitialized
|
||||
|
||||
@@ -31,10 +44,23 @@ abstract class UIActivity<Binding : ViewDataBinding> : BaseActivity(), ViewModel
|
||||
AppCompatDelegate.setDefaultNightMode(Config.darkTheme)
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(base.wrap())
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
layoutInflater.factory2 = LayoutInflaterFactory(delegate)
|
||||
.addOnViewCreatedListener(WindowInsetsHelper.LISTENER)
|
||||
|
||||
extension.onCreate(savedInstanceState)
|
||||
if (isRunningAsStub) {
|
||||
// Overwrite private members to avoid nasty "false" stack traces being logged
|
||||
val delegate = delegate
|
||||
val clz = delegate.javaClass
|
||||
clz.reflectField("mActivityHandlesConfigFlagsChecked").set(delegate, true)
|
||||
clz.reflectField("mActivityHandlesConfigFlags").set(delegate, 0)
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
startObserveLiveData()
|
||||
@@ -65,6 +91,11 @@ abstract class UIActivity<Binding : ViewDataBinding> : BaseActivity(), ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
extension.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
fun setContentView() {
|
||||
binding = DataBindingUtil.setContentView<Binding>(this, layoutRes).also {
|
||||
it.setVariable(BR.viewModel, viewModel)
|
||||
@@ -97,3 +128,14 @@ abstract class UIActivity<Binding : ViewDataBinding> : BaseActivity(), ViewModel
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
fun ViewGroup.startAnimations() {
|
||||
val transition = AutoTransition()
|
||||
.setInterpolator(FastOutSlowInInterpolator())
|
||||
.setDuration(400)
|
||||
.excludeTarget(R.id.main_toolbar, true)
|
||||
TransitionManager.beginDelayedTransition(
|
||||
this,
|
||||
transition
|
||||
)
|
||||
}
|
@@ -34,7 +34,8 @@ object VMFactory : ViewModelProvider.Factory {
|
||||
HomeViewModel::class.java -> HomeViewModel(ServiceLocator.networkService)
|
||||
LogViewModel::class.java -> LogViewModel(ServiceLocator.logRepo)
|
||||
SuperuserViewModel::class.java -> SuperuserViewModel(ServiceLocator.policyDB)
|
||||
InstallViewModel::class.java -> InstallViewModel(ServiceLocator.networkService)
|
||||
InstallViewModel::class.java ->
|
||||
InstallViewModel(ServiceLocator.networkService, ServiceLocator.markwon)
|
||||
SuRequestViewModel::class.java ->
|
||||
SuRequestViewModel(ServiceLocator.policyDB, ServiceLocator.timeoutPrefs)
|
||||
else -> modelClass.newInstance()
|
@@ -8,7 +8,12 @@ import android.text.Spanned
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.cardview.widget.CardView
|
||||
@@ -20,7 +25,11 @@ import androidx.databinding.BindingAdapter
|
||||
import androidx.databinding.InverseBindingAdapter
|
||||
import androidx.databinding.InverseBindingListener
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||
import androidx.recyclerview.widget.*
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.chip.Chip
|
@@ -6,22 +6,47 @@ import androidx.databinding.ListChangeRegistry
|
||||
import androidx.databinding.ObservableList
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListUpdateCallback
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.AbstractList
|
||||
|
||||
open class DiffObservableList<T : DiffItem<*>>
|
||||
: AbstractList<T>(), ObservableList<T>, ListUpdateCallback {
|
||||
// Only expose the immutable List types
|
||||
interface DiffList<T : DiffItem<*>> : List<T> {
|
||||
fun calculateDiff(newItems: List<T>): DiffUtil.DiffResult
|
||||
|
||||
@MainThread
|
||||
fun update(newItems: List<T>, diffResult: DiffUtil.DiffResult)
|
||||
|
||||
@WorkerThread
|
||||
suspend fun update(newItems: List<T>)
|
||||
}
|
||||
|
||||
interface FilterList<T : DiffItem<*>> : List<T> {
|
||||
fun filter(filter: (T) -> Boolean)
|
||||
|
||||
@MainThread
|
||||
fun set(newItems: List<T>)
|
||||
}
|
||||
|
||||
fun <T : DiffItem<*>> diffList(): DiffList<T> = DiffObservableList()
|
||||
|
||||
fun <T : DiffItem<*>> filterList(scope: CoroutineScope): FilterList<T> =
|
||||
FilterableDiffObservableList(scope)
|
||||
|
||||
private open class DiffObservableList<T : DiffItem<*>>
|
||||
: AbstractList<T>(), ObservableList<T>, DiffList<T>, ListUpdateCallback {
|
||||
|
||||
protected var list: List<T> = emptyList()
|
||||
private set
|
||||
private val listeners = ListChangeRegistry()
|
||||
|
||||
override val size: Int get() = list.size
|
||||
|
||||
override fun get(index: Int) = list[index]
|
||||
|
||||
fun calculateDiff(newItems: List<T>): DiffUtil.DiffResult {
|
||||
override fun calculateDiff(newItems: List<T>): DiffUtil.DiffResult {
|
||||
return doCalculateDiff(list, newItems)
|
||||
}
|
||||
|
||||
@@ -48,13 +73,13 @@ open class DiffObservableList<T : DiffItem<*>>
|
||||
}
|
||||
|
||||
@MainThread
|
||||
fun update(newItems: List<T>, diffResult: DiffUtil.DiffResult) {
|
||||
override fun update(newItems: List<T>, diffResult: DiffUtil.DiffResult) {
|
||||
list = ArrayList(newItems)
|
||||
diffResult.dispatchUpdatesTo(this)
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
suspend fun update(newItems: List<T>) {
|
||||
override suspend fun update(newItems: List<T>) {
|
||||
val diffResult = calculateDiff(newItems)
|
||||
withContext(Dispatchers.Main) {
|
||||
update(newItems, diffResult)
|
||||
@@ -87,3 +112,45 @@ open class DiffObservableList<T : DiffItem<*>>
|
||||
listeners.notifyRemoved(this, position, count)
|
||||
}
|
||||
}
|
||||
|
||||
private class FilterableDiffObservableList<T : DiffItem<*>>(
|
||||
private val scope: CoroutineScope
|
||||
) : DiffObservableList<T>(), FilterList<T> {
|
||||
|
||||
private var sublist: List<T> = emptyList()
|
||||
private var job: Job? = null
|
||||
private var lastFilter: ((T) -> Boolean)? = null
|
||||
|
||||
// ---
|
||||
|
||||
override fun filter(filter: (T) -> Boolean) {
|
||||
lastFilter = filter
|
||||
job?.cancel()
|
||||
job = scope.launch(Dispatchers.Default) {
|
||||
val oldList = sublist
|
||||
val newList = list.filter(filter)
|
||||
val diff = doCalculateDiff(oldList, newList)
|
||||
withContext(Dispatchers.Main) {
|
||||
sublist = newList
|
||||
diff.dispatchUpdatesTo(this@FilterableDiffObservableList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
override fun get(index: Int): T {
|
||||
return sublist[index]
|
||||
}
|
||||
|
||||
override val size: Int
|
||||
get() = sublist.size
|
||||
|
||||
@MainThread
|
||||
override fun set(newItems: List<T>) {
|
||||
onRemoved(0, sublist.size)
|
||||
list = newItems
|
||||
sublist = emptyList()
|
||||
lastFilter?.let { filter(it) }
|
||||
}
|
||||
}
|
@@ -3,7 +3,7 @@ package com.topjohnwu.magisk.databinding
|
||||
import androidx.databinding.ListChangeRegistry
|
||||
import androidx.databinding.ObservableList
|
||||
import androidx.databinding.ObservableList.OnListChangedCallback
|
||||
import java.util.*
|
||||
import java.util.AbstractList
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class MergeObservableList<T> : AbstractList<T>(), ObservableList<T> {
|
||||
@@ -46,11 +46,11 @@ class MergeObservableList<T> : AbstractList<T>(), ObservableList<T> {
|
||||
return this
|
||||
}
|
||||
|
||||
fun insertList(list: ObservableList<out T>): MergeObservableList<T> {
|
||||
fun insertList(list: List<T>): MergeObservableList<T> {
|
||||
val idx = size
|
||||
lists.add(list)
|
||||
++modCount
|
||||
(list as ObservableList<T>).addOnListChangedCallback(callback)
|
||||
(list as? ObservableList<T>)?.addOnListChangedCallback(callback)
|
||||
if (list.isNotEmpty())
|
||||
listeners.notifyInserted(this, idx, list.size)
|
||||
return this
|
||||
@@ -72,11 +72,11 @@ class MergeObservableList<T> : AbstractList<T>(), ObservableList<T> {
|
||||
return false
|
||||
}
|
||||
|
||||
fun removeList(listToRemove: ObservableList<out T>): Boolean {
|
||||
fun removeList(listToRemove: List<T>): Boolean {
|
||||
var idx = 0
|
||||
for ((i, list) in lists.withIndex()) {
|
||||
if (listToRemove === list) {
|
||||
(list as ObservableList<T>).removeOnListChangedCallback(callback)
|
||||
(list as? ObservableList<T>)?.removeOnListChangedCallback(callback)
|
||||
lists.removeAt(i)
|
||||
++modCount
|
||||
listeners.notifyRemoved(this, idx, list.size)
|
||||
@@ -90,8 +90,8 @@ class MergeObservableList<T> : AbstractList<T>(), ObservableList<T> {
|
||||
override fun clear() {
|
||||
val sz = size
|
||||
for (list in lists) {
|
||||
if (list is ObservableList<*>) {
|
||||
(list as ObservableList<T>).removeOnListChangedCallback(callback)
|
||||
if (list is ObservableList) {
|
||||
list.removeOnListChangedCallback(callback)
|
||||
}
|
||||
}
|
||||
++modCount
|
@@ -7,26 +7,27 @@ import com.topjohnwu.magisk.arch.UIActivity
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.events.DialogBuilder
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class DarkThemeDialog : DialogBuilder {
|
||||
|
||||
override fun build(dialog: MagiskDialog) {
|
||||
val activity = dialog.ownerActivity!!
|
||||
dialog.apply {
|
||||
setTitle(R.string.settings_dark_mode_title)
|
||||
setMessage(R.string.settings_dark_mode_message)
|
||||
setTitle(CoreR.string.settings_dark_mode_title)
|
||||
setMessage(CoreR.string.settings_dark_mode_message)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
text = R.string.settings_dark_mode_light
|
||||
text = CoreR.string.settings_dark_mode_light
|
||||
icon = R.drawable.ic_day
|
||||
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_NO, activity) }
|
||||
}
|
||||
setButton(MagiskDialog.ButtonType.NEUTRAL) {
|
||||
text = R.string.settings_dark_mode_system
|
||||
text = CoreR.string.settings_dark_mode_system
|
||||
icon = R.drawable.ic_day_night
|
||||
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM, activity) }
|
||||
}
|
||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
text = R.string.settings_dark_mode_dark
|
||||
text = CoreR.string.settings_dark_mode_dark
|
||||
icon = R.drawable.ic_night
|
||||
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_YES, activity) }
|
||||
}
|
@@ -1,10 +1,9 @@
|
||||
package com.topjohnwu.magisk.dialog
|
||||
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.BuildConfig
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
||||
import com.topjohnwu.magisk.events.DialogBuilder
|
||||
import com.topjohnwu.magisk.ui.home.HomeViewModel
|
||||
@@ -27,7 +26,7 @@ class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : Dialo
|
||||
resetButtons()
|
||||
setCancelable(false)
|
||||
}
|
||||
(dialog.ownerActivity as BaseActivity).lifecycleScope.launch {
|
||||
dialog.activity.lifecycleScope.launch {
|
||||
MagiskInstaller.FixEnv {
|
||||
dialog.dismiss()
|
||||
}.exec()
|
||||
@@ -40,8 +39,8 @@ class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : Dialo
|
||||
}
|
||||
|
||||
if (code == 2 || // No rules block, module policy not loaded
|
||||
Info.env.versionCode != BuildConfig.VERSION_CODE ||
|
||||
Info.env.versionString != BuildConfig.VERSION_NAME) {
|
||||
Info.env.versionCode != BuildConfig.APP_VERSION_CODE ||
|
||||
Info.env.versionString != BuildConfig.APP_VERSION_NAME) {
|
||||
dialog.setMessage(R.string.env_full_fix_msg)
|
||||
dialog.setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
text = android.R.string.ok
|
@@ -2,21 +2,21 @@ package com.topjohnwu.magisk.dialog
|
||||
|
||||
import android.net.Uri
|
||||
import com.topjohnwu.magisk.MainDirections
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.displayName
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.events.DialogBuilder
|
||||
import com.topjohnwu.magisk.ui.module.ModuleViewModel
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
|
||||
class LocalModuleInstallDialog(
|
||||
private val viewModel: ModuleViewModel,
|
||||
private val uri: Uri
|
||||
private val uri: Uri,
|
||||
private val displayName: String
|
||||
) : DialogBuilder {
|
||||
override fun build(dialog: MagiskDialog) {
|
||||
dialog.apply {
|
||||
setTitle(R.string.confirm_install_title)
|
||||
setMessage(context.getString(R.string.confirm_install, uri.displayName))
|
||||
setMessage(context.getString(R.string.confirm_install, displayName))
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
text = android.R.string.ok
|
||||
onClick {
|
@@ -1,10 +1,10 @@
|
||||
package com.topjohnwu.magisk.dialog
|
||||
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.AppContext
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import java.io.File
|
||||
@@ -29,7 +29,7 @@ class ManagerInstallDialog : MarkDownDialog() {
|
||||
setCancelable(true)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
text = R.string.install
|
||||
onClick { DownloadService.start(activity, Subject.App()) }
|
||||
onClick { DownloadEngine.startWithActivity(activity, Subject.App()) }
|
||||
}
|
||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
text = android.R.string.cancel
|
@@ -13,6 +13,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
abstract class MarkDownDialog : DialogBuilder {
|
||||
|
||||
@@ -30,7 +31,7 @@ abstract class MarkDownDialog : DialogBuilder {
|
||||
ServiceLocator.markwon.setMarkdown(tv, text)
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
tv.setText(R.string.download_file_error)
|
||||
tv.setText(CoreR.string.download_file_error)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
package com.topjohnwu.magisk.dialog
|
||||
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.download.Action
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
|
||||
class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog() {
|
||||
@@ -22,9 +22,9 @@ class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog
|
||||
dialog.apply {
|
||||
|
||||
fun download(install: Boolean) {
|
||||
val action = if (install) Action.Flash else Action.Download
|
||||
val subject = Subject.Module(item, action)
|
||||
DownloadService.start(activity, subject)
|
||||
val module = Subject.Module(item, install)
|
||||
module.piCreator = FlashFragment::installIntent
|
||||
DownloadEngine.startWithActivity(activity, module)
|
||||
}
|
||||
|
||||
val title = context.getString(R.string.repo_install_title,
|
@@ -1,6 +1,6 @@
|
||||
package com.topjohnwu.magisk.dialog
|
||||
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.events.DialogBuilder
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package com.topjohnwu.magisk.dialog
|
||||
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.events.DialogBuilder
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
|
@@ -3,11 +3,11 @@ package com.topjohnwu.magisk.dialog
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.NavigationActivity
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.events.DialogBuilder
|
||||
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
||||
@@ -38,9 +38,9 @@ class UninstallDialog : DialogBuilder {
|
||||
Shell.cmd("restore_imgs").submit { result ->
|
||||
dialog.dismiss()
|
||||
if (result.isSuccess) {
|
||||
Utils.toast(R.string.restore_done, Toast.LENGTH_SHORT)
|
||||
context.toast(R.string.restore_done, Toast.LENGTH_SHORT)
|
||||
} else {
|
||||
Utils.toast(R.string.restore_fail, Toast.LENGTH_LONG)
|
||||
context.toast(R.string.restore_fail, Toast.LENGTH_LONG)
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,6 +11,7 @@ import com.topjohnwu.magisk.arch.NavigationActivity
|
||||
import com.topjohnwu.magisk.arch.UIActivity
|
||||
import com.topjohnwu.magisk.arch.ViewEvent
|
||||
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
||||
import com.topjohnwu.magisk.core.base.relaunch
|
||||
import com.topjohnwu.magisk.utils.TextHolder
|
||||
import com.topjohnwu.magisk.utils.asText
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
@@ -47,7 +48,16 @@ class ShowUIEvent(private val delegate: View.AccessibilityDelegate?)
|
||||
|
||||
class RecreateEvent : ViewEvent(), ActivityExecutor {
|
||||
override fun invoke(activity: UIActivity<*>) {
|
||||
activity.recreate()
|
||||
activity.relaunch()
|
||||
}
|
||||
}
|
||||
|
||||
class AuthEvent(
|
||||
private val callback: () -> Unit
|
||||
) : ViewEvent(), ActivityExecutor {
|
||||
|
||||
override fun invoke(activity: UIActivity<*>) {
|
||||
activity.withAuthentication { if (it) callback() }
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package com.topjohnwu.magisk.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
@@ -8,6 +9,7 @@ import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.isGone
|
||||
@@ -17,30 +19,35 @@ import androidx.navigation.NavDirections
|
||||
import com.topjohnwu.magisk.MainDirections
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||
import com.topjohnwu.magisk.arch.NavigationActivity
|
||||
import com.topjohnwu.magisk.arch.startAnimations
|
||||
import com.topjohnwu.magisk.arch.viewModel
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.base.SplashController
|
||||
import com.topjohnwu.magisk.core.base.SplashScreenHost
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.core.tasks.AppMigration
|
||||
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
|
||||
import com.topjohnwu.magisk.ktx.startAnimations
|
||||
import com.topjohnwu.magisk.ui.home.HomeFragmentDirections
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class MainViewModel : BaseViewModel()
|
||||
|
||||
class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
||||
class MainActivity : NavigationActivity<ActivityMainMd2Binding>(), SplashScreenHost {
|
||||
|
||||
override val layoutRes = R.layout.activity_main_md2
|
||||
override val viewModel by viewModel<MainViewModel>()
|
||||
override val navHostId: Int = R.id.main_nav_host
|
||||
override val splashController = SplashController(this)
|
||||
override val snackbarView: View
|
||||
get() {
|
||||
val fragmentOverride = currentFragment?.snackbarView
|
||||
@@ -58,12 +65,23 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
||||
|
||||
private var isRootFragment = true
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTheme(Theme.selected.themeRes)
|
||||
splashController.preOnCreate()
|
||||
super.onCreate(savedInstanceState)
|
||||
splashController.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
splashController.onResume()
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
override fun showMainUI(savedInstanceState: Bundle?) {
|
||||
override fun onCreateUi(savedInstanceState: Bundle?) {
|
||||
setContentView()
|
||||
showUnsupportedMessage()
|
||||
askForHomeShortcut()
|
||||
checkStubComponent()
|
||||
|
||||
// Ask permission to post notifications for background update check
|
||||
if (Config.checkUpdate) {
|
||||
@@ -103,7 +121,7 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
||||
// https://issuetracker.google.com/issues/124538620
|
||||
}
|
||||
binding.mainNavigation.menu.apply {
|
||||
findItem(R.id.superuserFragment)?.isEnabled = Utils.showSuperUser()
|
||||
findItem(R.id.superuserFragment)?.isEnabled = Info.showSuperUser
|
||||
findItem(R.id.modulesFragment)?.isEnabled = Info.env.isActive && LocalModule.loaded()
|
||||
}
|
||||
|
||||
@@ -170,11 +188,36 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
override fun showInvalidStateMessage(): Unit = runOnUiThread {
|
||||
MagiskDialog(this).apply {
|
||||
setTitle(CoreR.string.unsupport_nonroot_stub_title)
|
||||
setMessage(CoreR.string.unsupport_nonroot_stub_msg)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
text = CoreR.string.install
|
||||
onClick {
|
||||
withPermission(REQUEST_INSTALL_PACKAGES) {
|
||||
if (!it) {
|
||||
toast(CoreR.string.install_unknown_denied, Toast.LENGTH_SHORT)
|
||||
showInvalidStateMessage()
|
||||
} else {
|
||||
lifecycleScope.launch {
|
||||
AppMigration.restore(this@MainActivity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setCancelable(false)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnsupportedMessage() {
|
||||
if (Info.env.isUnsupported) {
|
||||
MagiskDialog(this).apply {
|
||||
setTitle(R.string.unsupport_magisk_title)
|
||||
setMessage(R.string.unsupport_magisk_msg, Const.Version.MIN_VERSION)
|
||||
setTitle(CoreR.string.unsupport_magisk_title)
|
||||
setMessage(CoreR.string.unsupport_magisk_msg, Const.Version.MIN_VERSION)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
||||
setCancelable(false)
|
||||
}.show()
|
||||
@@ -185,8 +228,8 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
||||
?.filterNot { File("$it/magisk").exists() }
|
||||
?.any { File("$it/su").exists() } == true) {
|
||||
MagiskDialog(this).apply {
|
||||
setTitle(R.string.unsupport_general_title)
|
||||
setMessage(R.string.unsupport_other_su_msg)
|
||||
setTitle(CoreR.string.unsupport_general_title)
|
||||
setMessage(CoreR.string.unsupport_other_su_msg)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
||||
setCancelable(false)
|
||||
}.show()
|
||||
@@ -194,8 +237,8 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
||||
|
||||
if (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) {
|
||||
MagiskDialog(this).apply {
|
||||
setTitle(R.string.unsupport_general_title)
|
||||
setMessage(R.string.unsupport_system_app_msg)
|
||||
setTitle(CoreR.string.unsupport_general_title)
|
||||
setMessage(CoreR.string.unsupport_system_app_msg)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
||||
setCancelable(false)
|
||||
}.show()
|
||||
@@ -203,8 +246,8 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
||||
|
||||
if (applicationInfo.flags and ApplicationInfo.FLAG_EXTERNAL_STORAGE != 0) {
|
||||
MagiskDialog(this).apply {
|
||||
setTitle(R.string.unsupport_general_title)
|
||||
setMessage(R.string.unsupport_external_storage_msg)
|
||||
setTitle(CoreR.string.unsupport_general_title)
|
||||
setMessage(CoreR.string.unsupport_external_storage_msg)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
||||
setCancelable(false)
|
||||
}.show()
|
||||
@@ -217,8 +260,8 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
||||
// Ask and show dialog
|
||||
Config.askedHome = true
|
||||
MagiskDialog(this).apply {
|
||||
setTitle(R.string.add_shortcut_title)
|
||||
setMessage(R.string.add_shortcut_msg)
|
||||
setTitle(CoreR.string.add_shortcut_title)
|
||||
setMessage(CoreR.string.add_shortcut_msg)
|
||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
text = android.R.string.cancel
|
||||
}
|
||||
@@ -232,22 +275,4 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
private fun checkStubComponent() {
|
||||
if (intent.component?.className?.contains(HideAPK.PLACEHOLDER) == true) {
|
||||
// The stub APK was not properly patched, re-apply our changes
|
||||
withPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES) { granted ->
|
||||
if (granted) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val apk = File(applicationInfo.sourceDir)
|
||||
HideAPK.upgrade(this@MainActivity, apk)?.let {
|
||||
startActivity(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -4,15 +4,20 @@ import android.annotation.SuppressLint
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ComponentInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.*
|
||||
import android.content.pm.PackageManager.GET_ACTIVITIES
|
||||
import android.content.pm.PackageManager.GET_PROVIDERS
|
||||
import android.content.pm.PackageManager.GET_RECEIVERS
|
||||
import android.content.pm.PackageManager.GET_SERVICES
|
||||
import android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS
|
||||
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import androidx.core.os.ProcessCompat
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import com.topjohnwu.magisk.ktx.getLabel
|
||||
import java.util.*
|
||||
import com.topjohnwu.magisk.core.ktx.getLabel
|
||||
import java.util.Locale
|
||||
import java.util.TreeSet
|
||||
|
||||
class CmdlineListItem(line: String) {
|
||||
val packageName: String
|
||||
@@ -97,7 +102,7 @@ class AppProcessInfo(
|
||||
|
||||
companion object {
|
||||
private val comparator = compareBy<AppProcessInfo>(
|
||||
{ it.label.lowercase(currentLocale) },
|
||||
{ it.label.lowercase(Locale.ROOT) },
|
||||
{ it.info.packageName }
|
||||
)
|
||||
}
|
@@ -11,11 +11,12 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseFragment
|
||||
import com.topjohnwu.magisk.arch.viewModel
|
||||
import com.topjohnwu.magisk.core.ktx.hideKeyboard
|
||||
import com.topjohnwu.magisk.databinding.FragmentDenyMd2Binding
|
||||
import com.topjohnwu.magisk.ktx.hideKeyboard
|
||||
import rikka.recyclerview.addEdgeSpacing
|
||||
import rikka.recyclerview.addItemSpacing
|
||||
import rikka.recyclerview.fixEdgeEffect
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>(), MenuProvider {
|
||||
|
||||
@@ -26,7 +27,7 @@ class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>(), MenuProvider {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity?.setTitle(R.string.denylist)
|
||||
activity?.setTitle(CoreR.string.denylist)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -58,7 +59,7 @@ class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>(), MenuProvider {
|
||||
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.menu_deny_md2, menu)
|
||||
searchView = menu.findItem(R.id.action_search).actionView as SearchView
|
||||
searchView.queryHint = searchView.context.getString(R.string.hide_filter_hint)
|
||||
searchView.queryHint = searchView.context.getString(CoreR.string.hide_filter_hint)
|
||||
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||
viewModel.query = query ?: ""
|
@@ -5,11 +5,11 @@ import android.view.ViewGroup
|
||||
import androidx.databinding.Bindable
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.startAnimations
|
||||
import com.topjohnwu.magisk.databinding.DiffItem
|
||||
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||
import com.topjohnwu.magisk.databinding.addOnPropertyChangedCallback
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.ktx.startAnimations
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlin.math.roundToInt
|
||||
|
@@ -6,11 +6,11 @@ import androidx.databinding.Bindable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import com.topjohnwu.magisk.databinding.FilterableDiffObservableList
|
||||
import com.topjohnwu.magisk.core.AppContext
|
||||
import com.topjohnwu.magisk.core.ktx.concurrentMap
|
||||
import com.topjohnwu.magisk.databinding.bindExtra
|
||||
import com.topjohnwu.magisk.databinding.filterList
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.ktx.concurrentMap
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
@@ -23,22 +23,22 @@ class DenyListViewModel : AsyncLoadViewModel() {
|
||||
var isShowSystem = false
|
||||
set(value) {
|
||||
field = value
|
||||
query()
|
||||
doQuery(query)
|
||||
}
|
||||
|
||||
var isShowOS = false
|
||||
set(value) {
|
||||
field = value
|
||||
query()
|
||||
doQuery(query)
|
||||
}
|
||||
|
||||
var query = ""
|
||||
set(value) {
|
||||
field = value
|
||||
query()
|
||||
doQuery(value)
|
||||
}
|
||||
|
||||
val items = FilterableDiffObservableList<DenyListRvItem>(viewModelScope)
|
||||
val items = filterList<DenyListRvItem>(viewModelScope)
|
||||
val extraBindings = bindExtra {
|
||||
it.put(BR.viewModel, this)
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class DenyListViewModel : AsyncLoadViewModel() {
|
||||
@SuppressLint("InlinedApi")
|
||||
override suspend fun doLoadWork() {
|
||||
loading = true
|
||||
withContext(Dispatchers.Default) {
|
||||
val apps = withContext(Dispatchers.Default) {
|
||||
val pm = AppContext.packageManager
|
||||
val denyList = Shell.cmd("magisk --denylist ls").exec().out
|
||||
.map { CmdlineListItem(it) }
|
||||
@@ -63,21 +63,22 @@ class DenyListViewModel : AsyncLoadViewModel() {
|
||||
.toCollection(ArrayList(size))
|
||||
}
|
||||
apps.sort()
|
||||
items.update(apps)
|
||||
apps
|
||||
}
|
||||
query()
|
||||
items.set(apps)
|
||||
doQuery(query)
|
||||
}
|
||||
|
||||
private fun query() {
|
||||
private fun doQuery(s: String) {
|
||||
items.filter {
|
||||
fun filterSystem() = isShowSystem || !it.info.isSystemApp()
|
||||
|
||||
fun filterOS() = (isShowSystem && isShowOS) || it.info.isApp()
|
||||
|
||||
fun filterQuery(): Boolean {
|
||||
fun inName() = it.info.label.contains(query, true)
|
||||
fun inPackage() = it.info.packageName.contains(query, true)
|
||||
fun inProcesses() = it.processes.any { p -> p.process.name.contains(query, true) }
|
||||
fun inName() = it.info.label.contains(s, true)
|
||||
fun inPackage() = it.info.packageName.contains(s, true)
|
||||
fun inProcesses() = it.processes.any { p -> p.process.name.contains(s, true) }
|
||||
return inName() || inPackage() || inProcesses()
|
||||
}
|
||||
|
@@ -5,7 +5,11 @@ import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.navigation.NavDeepLinkBuilder
|
||||
@@ -17,6 +21,7 @@ import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.cmp
|
||||
import com.topjohnwu.magisk.databinding.FragmentFlashMd2Binding
|
||||
import com.topjohnwu.magisk.ui.MainActivity
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class FlashFragment : BaseFragment<FragmentFlashMd2Binding>(), MenuProvider {
|
||||
|
||||
@@ -35,14 +40,14 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>(), MenuProvider {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity?.setTitle(R.string.flash_screen_title)
|
||||
activity?.setTitle(CoreR.string.flash_screen_title)
|
||||
|
||||
viewModel.state.observe(this) {
|
||||
activity?.supportActionBar?.setSubtitle(
|
||||
when (it) {
|
||||
FlashViewModel.State.FLASHING -> R.string.flashing
|
||||
FlashViewModel.State.SUCCESS -> R.string.done
|
||||
FlashViewModel.State.FAILED -> R.string.failure
|
||||
FlashViewModel.State.FLASHING -> CoreR.string.flashing
|
||||
FlashViewModel.State.SUCCESS -> CoreR.string.done
|
||||
FlashViewModel.State.FAILED -> CoreR.string.failure
|
||||
}
|
||||
)
|
||||
if (it == FlashViewModel.State.SUCCESS && viewModel.showReboot) {
|
@@ -5,23 +5,23 @@ import androidx.databinding.Bindable
|
||||
import androidx.databinding.ObservableArrayList
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import androidx.lifecycle.map
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.ktx.reboot
|
||||
import com.topjohnwu.magisk.core.ktx.synchronized
|
||||
import com.topjohnwu.magisk.core.ktx.timeFormatStandard
|
||||
import com.topjohnwu.magisk.core.ktx.toTime
|
||||
import com.topjohnwu.magisk.core.tasks.FlashZip
|
||||
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.ktx.reboot
|
||||
import com.topjohnwu.magisk.ktx.synchronized
|
||||
import com.topjohnwu.magisk.ktx.timeFormatStandard
|
||||
import com.topjohnwu.magisk.ktx.toTime
|
||||
import com.topjohnwu.superuser.CallbackList
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -34,7 +34,7 @@ class FlashViewModel : BaseViewModel() {
|
||||
|
||||
private val _state = MutableLiveData(State.FLASHING)
|
||||
val state: LiveData<State> get() = _state
|
||||
val flashing = Transformations.map(state) { it == State.FLASHING }
|
||||
val flashing = state.map { it == State.FLASHING }
|
||||
|
||||
@get:Bindable
|
||||
var showReboot = Info.isRooted
|
||||
@@ -72,6 +72,7 @@ class FlashViewModel : BaseViewModel() {
|
||||
MagiskInstaller.Direct(outItems, logItems).exec()
|
||||
}
|
||||
Const.Value.FLASH_INACTIVE_SLOT -> {
|
||||
showReboot = false
|
||||
MagiskInstaller.SecondSlot(outItems, logItems).exec()
|
||||
}
|
||||
Const.Value.PATCH_FILE -> {
|
||||
@@ -104,7 +105,7 @@ class FlashViewModel : BaseViewModel() {
|
||||
val name = "magisk_install_log_%s.log".format(
|
||||
System.currentTimeMillis().toTime(timeFormatStandard)
|
||||
)
|
||||
val file = MediaStoreUtils.getFile(name, true)
|
||||
val file = MediaStoreUtils.getFile(name)
|
||||
file.uri.outputStream().bufferedWriter().use { writer ->
|
||||
synchronized(logItems) {
|
||||
logItems.forEach {
|
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.ui.home
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.databinding.RvItem
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
interface Dev {
|
||||
val name: String
|
||||
@@ -24,6 +25,10 @@ private interface RikkaImpl : Dev {
|
||||
override val name get() = "RikkaW"
|
||||
}
|
||||
|
||||
private interface CanyieImpl : Dev {
|
||||
override val name get() = "canyie"
|
||||
}
|
||||
|
||||
sealed class DeveloperItem : Dev {
|
||||
|
||||
abstract val items: List<IconLink>
|
||||
@@ -61,6 +66,14 @@ sealed class DeveloperItem : Dev {
|
||||
object : IconLink.Github.User(), RikkaImpl {}
|
||||
)
|
||||
}
|
||||
|
||||
object Canyie : DeveloperItem(), CanyieImpl {
|
||||
override val items =
|
||||
listOf<IconLink>(
|
||||
object : IconLink.Twitter() { override val name = "canyie2977" },
|
||||
object : IconLink.Github.User(), CanyieImpl {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class IconLink : RvItem() {
|
||||
@@ -72,8 +85,8 @@ sealed class IconLink : RvItem() {
|
||||
override val layoutRes get() = R.layout.item_icon_link
|
||||
|
||||
abstract class PayPal : IconLink(), Dev {
|
||||
override val icon get() = R.drawable.ic_paypal
|
||||
override val title get() = R.string.paypal
|
||||
override val icon get() = CoreR.drawable.ic_paypal
|
||||
override val title get() = CoreR.string.paypal
|
||||
override val link get() = "https://paypal.me/$name"
|
||||
|
||||
object Project : PayPal() {
|
||||
@@ -82,20 +95,20 @@ sealed class IconLink : RvItem() {
|
||||
}
|
||||
|
||||
object Patreon : IconLink() {
|
||||
override val icon get() = R.drawable.ic_patreon
|
||||
override val title get() = R.string.patreon
|
||||
override val icon get() = CoreR.drawable.ic_patreon
|
||||
override val title get() = CoreR.string.patreon
|
||||
override val link get() = Const.Url.PATREON_URL
|
||||
}
|
||||
|
||||
abstract class Twitter : IconLink(), Dev {
|
||||
override val icon get() = R.drawable.ic_twitter
|
||||
override val title get() = R.string.twitter
|
||||
override val icon get() = CoreR.drawable.ic_twitter
|
||||
override val title get() = CoreR.string.twitter
|
||||
override val link get() = "https://twitter.com/$name"
|
||||
}
|
||||
|
||||
abstract class Github : IconLink() {
|
||||
override val icon get() = R.drawable.ic_github
|
||||
override val title get() = R.string.github
|
||||
override val icon get() = CoreR.drawable.ic_github
|
||||
override val title get() = CoreR.string.github
|
||||
|
||||
abstract class User : Github(), Dev {
|
||||
override val link get() = "https://github.com/$name"
|
||||
@@ -107,8 +120,8 @@ sealed class IconLink : RvItem() {
|
||||
}
|
||||
|
||||
abstract class Sponsor : IconLink(), Dev {
|
||||
override val icon get() = R.drawable.ic_favorite
|
||||
override val title get() = R.string.github
|
||||
override val icon get() = CoreR.drawable.ic_favorite
|
||||
override val title get() = CoreR.string.github
|
||||
override val link get() = "https://github.com/sponsors/$name"
|
||||
}
|
||||
}
|
@@ -14,8 +14,9 @@ import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseFragment
|
||||
import com.topjohnwu.magisk.arch.viewModel
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||
import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider {
|
||||
|
||||
@@ -24,8 +25,8 @@ class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity?.setTitle(R.string.section_home)
|
||||
DownloadService.observeProgress(this, viewModel::onProgressUpdate)
|
||||
activity?.setTitle(CoreR.string.section_home)
|
||||
DownloadEngine.observeProgress(this, viewModel::onProgressUpdate)
|
||||
}
|
||||
|
||||
private fun checkTitle(text: TextView, icon: ImageView) {
|
@@ -1,20 +1,25 @@
|
||||
package com.topjohnwu.magisk.ui.home
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import androidx.core.net.toUri
|
||||
import androidx.databinding.Bindable
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.ActivityExecutor
|
||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||
import com.topjohnwu.magisk.arch.ContextExecutor
|
||||
import com.topjohnwu.magisk.arch.UIActivity
|
||||
import com.topjohnwu.magisk.arch.ViewEvent
|
||||
import com.topjohnwu.magisk.core.BuildConfig
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.download.Subject
|
||||
import com.topjohnwu.magisk.core.download.Subject.App
|
||||
import com.topjohnwu.magisk.core.ktx.await
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.repository.NetworkService
|
||||
import com.topjohnwu.magisk.databinding.bindExtra
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
@@ -22,11 +27,10 @@ import com.topjohnwu.magisk.dialog.EnvFixDialog
|
||||
import com.topjohnwu.magisk.dialog.ManagerInstallDialog
|
||||
import com.topjohnwu.magisk.dialog.UninstallDialog
|
||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.ktx.await
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.asText
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlin.math.roundToInt
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class HomeViewModel(
|
||||
private val svc: NetworkService
|
||||
@@ -49,7 +53,7 @@ class HomeViewModel(
|
||||
get() = when {
|
||||
Info.isRooted && Info.env.isUnsupported -> State.OUTDATED
|
||||
!Info.env.isActive -> State.INVALID
|
||||
Info.env.versionCode < BuildConfig.VERSION_CODE -> State.OUTDATED
|
||||
Info.env.versionCode < BuildConfig.APP_VERSION_CODE -> State.OUTDATED
|
||||
else -> State.UP_TO_DATE
|
||||
}
|
||||
|
||||
@@ -62,15 +66,15 @@ class HomeViewModel(
|
||||
if (isActive)
|
||||
("$versionString ($versionCode)" + if (isDebug) " (D)" else "").asText()
|
||||
else
|
||||
R.string.not_available.asText()
|
||||
CoreR.string.not_available.asText()
|
||||
}
|
||||
|
||||
@get:Bindable
|
||||
var managerRemoteVersion = R.string.loading.asText()
|
||||
var managerRemoteVersion = CoreR.string.loading.asText()
|
||||
set(value) = set(value, field, { field = it }, BR.managerRemoteVersion)
|
||||
|
||||
val managerInstalledVersion
|
||||
get() = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" +
|
||||
get() = "${BuildConfig.APP_VERSION_NAME} (${BuildConfig.APP_VERSION_CODE})" +
|
||||
if (BuildConfig.DEBUG) " (D)" else ""
|
||||
|
||||
@get:Bindable
|
||||
@@ -89,7 +93,7 @@ class HomeViewModel(
|
||||
appState = State.LOADING
|
||||
Info.getRemote(svc)?.apply {
|
||||
appState = when {
|
||||
BuildConfig.VERSION_CODE < magisk.versionCode -> State.OUTDATED
|
||||
BuildConfig.APP_VERSION_CODE < magisk.versionCode -> State.OUTDATED
|
||||
else -> State.UP_TO_DATE
|
||||
}
|
||||
|
||||
@@ -99,7 +103,7 @@ class HomeViewModel(
|
||||
if (isDebug) " (D)" else "").asText()
|
||||
} ?: run {
|
||||
appState = State.INVALID
|
||||
managerRemoteVersion = R.string.not_available.asText()
|
||||
managerRemoteVersion = CoreR.string.not_available.asText()
|
||||
}
|
||||
ensureEnv()
|
||||
}
|
||||
@@ -112,14 +116,22 @@ class HomeViewModel(
|
||||
}
|
||||
|
||||
fun onLinkPressed(link: String) = object : ViewEvent(), ContextExecutor {
|
||||
override fun invoke(context: Context) = Utils.openLink(context, link.toUri())
|
||||
override fun invoke(context: Context) {
|
||||
val intent = Intent(Intent.ACTION_VIEW, link.toUri())
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
try {
|
||||
context.startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
context.toast(CoreR.string.open_link_failed_toast, Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
}.publish()
|
||||
|
||||
fun onDeletePressed() = UninstallDialog().show()
|
||||
|
||||
fun onManagerPressed() = when (appState) {
|
||||
State.LOADING -> SnackbarEvent(R.string.loading).publish()
|
||||
State.INVALID -> SnackbarEvent(R.string.no_connection).publish()
|
||||
State.LOADING -> SnackbarEvent(CoreR.string.loading).publish()
|
||||
State.INVALID -> SnackbarEvent(CoreR.string.no_connection).publish()
|
||||
else -> withExternalRW {
|
||||
withInstallPermission {
|
||||
ManagerInstallDialog().show()
|
@@ -1,5 +1,6 @@
|
||||
package com.topjohnwu.magisk.ui.home
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import android.view.ContextThemeWrapper
|
||||
@@ -7,8 +8,9 @@ import android.view.MenuItem
|
||||
import android.widget.PopupMenu
|
||||
import androidx.core.content.getSystemService
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.ktx.reboot as systemReboot
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.ktx.reboot as systemReboot
|
||||
|
||||
object RebootMenu {
|
||||
|
||||
@@ -20,19 +22,30 @@ object RebootMenu {
|
||||
R.id.action_reboot_download -> systemReboot("download")
|
||||
R.id.action_reboot_edl -> systemReboot("edl")
|
||||
R.id.action_reboot_recovery -> systemReboot("recovery")
|
||||
R.id.action_reboot_safe_mode -> {
|
||||
val status = !item.isChecked
|
||||
item.isChecked = status
|
||||
Config.bootloop = if (status) 2 else 0
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun inflate(activity: BaseActivity): PopupMenu {
|
||||
fun inflate(activity: Activity): PopupMenu {
|
||||
val themeWrapper = ContextThemeWrapper(activity, R.style.Foundation_PopupMenu)
|
||||
val menu = PopupMenu(themeWrapper, activity.findViewById(R.id.action_reboot))
|
||||
activity.menuInflater.inflate(R.menu.menu_reboot, menu.menu)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||
activity.getSystemService<PowerManager>()?.isRebootingUserspaceSupported == true)
|
||||
menu.menu.findItem(R.id.action_reboot_userspace).isVisible = true
|
||||
menu.setOnMenuItemClickListener(RebootMenu::reboot)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
|
||||
activity.getSystemService<PowerManager>()?.isRebootingUserspaceSupported == true) {
|
||||
menu.menu.findItem(R.id.action_reboot_userspace).isVisible = true
|
||||
}
|
||||
if (Const.Version.isCanary()) {
|
||||
menu.menu.findItem(R.id.action_reboot_safe_mode).isChecked = Config.bootloop >= 2
|
||||
} else {
|
||||
menu.menu.findItem(R.id.action_reboot_safe_mode).isVisible = false
|
||||
}
|
||||
return menu
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseFragment
|
||||
import com.topjohnwu.magisk.arch.viewModel
|
||||
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class InstallFragment : BaseFragment<FragmentInstallMd2Binding>() {
|
||||
|
||||
@@ -12,6 +13,6 @@ class InstallFragment : BaseFragment<FragmentInstallMd2Binding>() {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
requireActivity().setTitle(R.string.install)
|
||||
requireActivity().setTitle(CoreR.string.install)
|
||||
}
|
||||
}
|
@@ -3,43 +3,42 @@ package com.topjohnwu.magisk.ui.install
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.SpannedString
|
||||
import android.widget.Toast
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||
import com.topjohnwu.magisk.core.AppContext
|
||||
import com.topjohnwu.magisk.core.BuildConfig
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
||||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.repository.NetworkService
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.dialog.SecondSlotWarningDialog
|
||||
import com.topjohnwu.magisk.events.GetContentEvent
|
||||
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import io.noties.markwon.Markwon
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class InstallViewModel(
|
||||
svc: NetworkService
|
||||
) : BaseViewModel() {
|
||||
class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel() {
|
||||
|
||||
val isRooted get() = Info.isRooted
|
||||
val hideVbmeta = Info.vbmeta || Info.isSamsung || Info.isAB
|
||||
val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && hideVbmeta && Info.ramdisk)
|
||||
val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && Info.ramdisk)
|
||||
val noSecondSlot = !isRooted || !Info.isAB || Info.isEmulator
|
||||
|
||||
@get:Bindable
|
||||
@@ -65,13 +64,13 @@ class InstallViewModel(
|
||||
val data: LiveData<Uri?> get() = uri
|
||||
|
||||
@get:Bindable
|
||||
var notes: Spanned = SpannableStringBuilder()
|
||||
var notes: Spanned = SpannedString("")
|
||||
set(value) = set(value, field, { field = it }, BR.notes)
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val file = File(AppContext.cacheDir, "${BuildConfig.VERSION_CODE}.md")
|
||||
val file = File(AppContext.cacheDir, "${BuildConfig.APP_VERSION_CODE}.md")
|
||||
val text = when {
|
||||
file.exists() -> file.readText()
|
||||
Const.Url.CHANGELOG_URL.isEmpty() -> ""
|
||||
@@ -81,7 +80,10 @@ class InstallViewModel(
|
||||
str
|
||||
}
|
||||
}
|
||||
notes = ServiceLocator.markwon.toMarkdown(text)
|
||||
val spanned = markwon.toMarkdown(text)
|
||||
withContext(Dispatchers.Main) {
|
||||
notes = spanned
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
}
|
||||
@@ -103,7 +105,6 @@ class InstallViewModel(
|
||||
step,
|
||||
Config.keepVerity,
|
||||
Config.keepEnc,
|
||||
Config.patchVbmeta,
|
||||
Config.recovery
|
||||
))
|
||||
}
|
||||
@@ -114,7 +115,6 @@ class InstallViewModel(
|
||||
step = it.step
|
||||
Config.keepVerity = it.keepVerity
|
||||
Config.keepEnc = it.keepEnc
|
||||
Config.patchVbmeta = it.patchVbmeta
|
||||
Config.recovery = it.recovery
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ class InstallViewModel(
|
||||
@Parcelize
|
||||
class UriCallback : ContentResultCallback {
|
||||
override fun onActivityLaunch() {
|
||||
Utils.toast(R.string.patch_file_msg, Toast.LENGTH_LONG)
|
||||
AppContext.toast(CoreR.string.patch_file_msg, Toast.LENGTH_LONG)
|
||||
}
|
||||
override fun onActivityResult(result: Uri) {
|
||||
uri.value = result
|
||||
@@ -135,7 +135,6 @@ class InstallViewModel(
|
||||
val step: Int,
|
||||
val keepVerity: Boolean,
|
||||
val keepEnc: Boolean,
|
||||
val patchVbmeta: Boolean,
|
||||
val recovery: Boolean,
|
||||
) : Parcelable
|
||||
|
@@ -16,6 +16,7 @@ import com.topjohnwu.magisk.utils.MotionRevealHelper
|
||||
import rikka.recyclerview.addEdgeSpacing
|
||||
import rikka.recyclerview.addItemSpacing
|
||||
import rikka.recyclerview.fixEdgeEffect
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class LogFragment : BaseFragment<FragmentLogMd2Binding>(), MenuProvider {
|
||||
|
||||
@@ -41,7 +42,7 @@ class LogFragment : BaseFragment<FragmentLogMd2Binding>(), MenuProvider {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity?.setTitle(R.string.logs)
|
||||
activity?.setTitle(CoreR.string.logs)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
@@ -4,19 +4,19 @@ import android.system.Os
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||
import com.topjohnwu.magisk.core.BuildConfig
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.ktx.timeFormatStandard
|
||||
import com.topjohnwu.magisk.core.ktx.toTime
|
||||
import com.topjohnwu.magisk.core.repository.LogRepository
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||
import com.topjohnwu.magisk.databinding.DiffObservableList
|
||||
import com.topjohnwu.magisk.databinding.bindExtra
|
||||
import com.topjohnwu.magisk.databinding.diffList
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.ktx.timeFormatStandard
|
||||
import com.topjohnwu.magisk.ktx.toTime
|
||||
import com.topjohnwu.magisk.view.TextItem
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -37,13 +37,13 @@ class LogViewModel(
|
||||
|
||||
// --- su log
|
||||
|
||||
val items = DiffObservableList<SuLogRvItem>()
|
||||
val items = diffList<SuLogRvItem>()
|
||||
val extraBindings = bindExtra {
|
||||
it.put(BR.viewModel, this)
|
||||
}
|
||||
|
||||
// --- magisk log
|
||||
val logs = DiffObservableList<LogRvItem>()
|
||||
val logs = diffList<LogRvItem>()
|
||||
var magiskLogRaw = " "
|
||||
|
||||
override suspend fun doLoadWork() {
|
||||
@@ -69,7 +69,7 @@ class LogViewModel(
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val filename = "magisk_log_%s.log".format(
|
||||
System.currentTimeMillis().toTime(timeFormatStandard))
|
||||
val logFile = MediaStoreUtils.getFile(filename, true)
|
||||
val logFile = MediaStoreUtils.getFile(filename)
|
||||
logFile.uri.outputStream().bufferedWriter().use { file ->
|
||||
file.write("---Detected Device Info---\n\n")
|
||||
file.write("isAB=${Info.isAB}\n")
|
||||
@@ -93,7 +93,7 @@ class LogViewModel(
|
||||
if (Info.env.isActive) file.write(magiskLogRaw)
|
||||
|
||||
file.write("\n---Manager Logs---\n")
|
||||
file.write("${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})\n\n")
|
||||
file.write("${BuildConfig.APP_VERSION_NAME} (${BuildConfig.APP_VERSION_CODE})\n\n")
|
||||
ProcessBuilder("logcat", "-d").start()
|
||||
.inputStream.reader().use { it.copyTo(file) }
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package com.topjohnwu.magisk.ui.log
|
||||
|
||||
import androidx.databinding.Bindable
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.AppContext
|
||||
import com.topjohnwu.magisk.core.ktx.timeDateFormat
|
||||
import com.topjohnwu.magisk.core.ktx.toTime
|
||||
import com.topjohnwu.magisk.core.model.su.SuLog
|
||||
import com.topjohnwu.magisk.databinding.DiffItem
|
||||
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class SuLogRvItem(val log: SuLog) : ObservableRvItem(), DiffItem<SuLogRvItem> {
|
||||
|
||||
override val layoutRes = R.layout.item_log_access_md2
|
||||
|
||||
val info = genInfo()
|
||||
|
||||
@get:Bindable
|
||||
var isTop = false
|
||||
set(value) = set(value, field, { field = it }, BR.top)
|
||||
|
||||
@get:Bindable
|
||||
var isBottom = false
|
||||
set(value) = set(value, field, { field = it }, BR.bottom)
|
||||
|
||||
override fun itemSameAs(other: SuLogRvItem) = log.appName == other.log.appName
|
||||
|
||||
private fun genInfo(): String {
|
||||
val res = AppContext.resources
|
||||
val sb = StringBuilder()
|
||||
val date = log.time.toTime(timeDateFormat)
|
||||
val toUid = res.getString(CoreR.string.target_uid, log.toUid)
|
||||
val fromPid = res.getString(CoreR.string.pid, log.fromPid)
|
||||
sb.append("$date\n$toUid $fromPid")
|
||||
if (log.target != -1) {
|
||||
val pid = if (log.target == 0) "magiskd" else log.target.toString()
|
||||
val target = res.getString(CoreR.string.target_pid, pid)
|
||||
sb.append(" $target")
|
||||
}
|
||||
if (log.context.isNotEmpty()) {
|
||||
val context = res.getString(CoreR.string.selinux_context, log.context)
|
||||
sb.append("\n$context")
|
||||
}
|
||||
if (log.gids.isNotEmpty()) {
|
||||
val gids = res.getString(CoreR.string.supp_group, log.gids)
|
||||
sb.append("\n$gids")
|
||||
}
|
||||
sb.append("\n${log.command}")
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
@@ -5,11 +5,13 @@ import android.view.View
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseFragment
|
||||
import com.topjohnwu.magisk.arch.viewModel
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.displayName
|
||||
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
|
||||
import rikka.recyclerview.addEdgeSpacing
|
||||
import rikka.recyclerview.addInvalidateItemDecorationsObserver
|
||||
import rikka.recyclerview.addItemSpacing
|
||||
import rikka.recyclerview.fixEdgeEffect
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class ModuleFragment : BaseFragment<FragmentModuleMd2Binding>() {
|
||||
|
||||
@@ -18,10 +20,11 @@ class ModuleFragment : BaseFragment<FragmentModuleMd2Binding>() {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity?.title = resources.getString(R.string.modules)
|
||||
activity?.title = resources.getString(CoreR.string.modules)
|
||||
viewModel.data.observe(this) {
|
||||
it ?: return@observe
|
||||
viewModel.requestInstallLocalModule(it)
|
||||
val displayName = runCatching { it.displayName }.getOrNull() ?: return@observe
|
||||
viewModel.requestInstallLocalModule(it, displayName)
|
||||
viewModel.data.value = null
|
||||
}
|
||||
}
|
@@ -12,6 +12,7 @@ import com.topjohnwu.magisk.databinding.RvItem
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.utils.TextHolder
|
||||
import com.topjohnwu.magisk.utils.asText
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
object InstallModule : RvItem(), DiffItem<InstallModule> {
|
||||
override val layoutRes = R.layout.item_module_download
|
||||
@@ -36,9 +37,9 @@ class LocalModuleRvItem(
|
||||
(!Info.isZygiskEnabled && isZygisk)
|
||||
noticeText =
|
||||
when {
|
||||
zygiskUnloaded -> R.string.zygisk_module_unloaded.asText()
|
||||
isRiru -> R.string.suspend_text_riru.asText(R.string.zygisk.asText())
|
||||
else -> R.string.suspend_text_zygisk.asText(R.string.zygisk.asText())
|
||||
zygiskUnloaded -> CoreR.string.zygisk_module_unloaded.asText()
|
||||
isRiru -> CoreR.string.suspend_text_riru.asText(CoreR.string.zygisk.asText())
|
||||
else -> CoreR.string.suspend_text_zygisk.asText(CoreR.string.zygisk.asText())
|
||||
}
|
||||
}
|
||||
|
@@ -10,10 +10,10 @@ import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||
import com.topjohnwu.magisk.databinding.DiffObservableList
|
||||
import com.topjohnwu.magisk.databinding.MergeObservableList
|
||||
import com.topjohnwu.magisk.databinding.RvItem
|
||||
import com.topjohnwu.magisk.databinding.bindExtra
|
||||
import com.topjohnwu.magisk.databinding.diffList
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.dialog.LocalModuleInstallDialog
|
||||
import com.topjohnwu.magisk.dialog.OnlineModuleInstallDialog
|
||||
@@ -22,12 +22,13 @@ import com.topjohnwu.magisk.events.SnackbarEvent
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class ModuleViewModel : AsyncLoadViewModel() {
|
||||
|
||||
val bottomBarBarrierIds = intArrayOf(R.id.module_update, R.id.module_remove)
|
||||
|
||||
private val itemsInstalled = DiffObservableList<LocalModuleRvItem>()
|
||||
private val itemsInstalled = diffList<LocalModuleRvItem>()
|
||||
|
||||
val items = MergeObservableList<RvItem>()
|
||||
val extraBindings = bindExtra {
|
||||
@@ -77,15 +78,15 @@ class ModuleViewModel : AsyncLoadViewModel() {
|
||||
if (item != null && Info.isConnected.value == true) {
|
||||
withExternalRW { OnlineModuleInstallDialog(item).show() }
|
||||
} else {
|
||||
SnackbarEvent(R.string.no_connection).publish()
|
||||
SnackbarEvent(CoreR.string.no_connection).publish()
|
||||
}
|
||||
|
||||
fun installPressed() = withExternalRW {
|
||||
GetContentEvent("application/zip", UriCallback()).publish()
|
||||
}
|
||||
|
||||
fun requestInstallLocalModule(uri: Uri) {
|
||||
LocalModuleInstallDialog(this, uri).show()
|
||||
fun requestInstallLocalModule(uri: Uri, displayName: String) {
|
||||
LocalModuleInstallDialog(this, uri, displayName).show()
|
||||
}
|
||||
|
||||
@Parcelize
|
@@ -6,37 +6,42 @@ import android.view.View
|
||||
import androidx.databinding.Bindable
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.ktx.activity
|
||||
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.ktx.activity
|
||||
import com.topjohnwu.magisk.utils.TextHolder
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
|
||||
sealed class BaseSettingsItem : ObservableRvItem() {
|
||||
|
||||
interface Handler {
|
||||
fun onItemPressed(view: View, item: BaseSettingsItem, andThen: () -> Unit)
|
||||
fun onItemAction(view: View, item: BaseSettingsItem)
|
||||
}
|
||||
|
||||
override val layoutRes get() = R.layout.item_settings
|
||||
|
||||
open val icon: Int get() = 0
|
||||
open val title: TextHolder get() = TextHolder.EMPTY
|
||||
@get:Bindable
|
||||
open val description: TextHolder get() = TextHolder.EMPTY
|
||||
open val showSwitch get() = false
|
||||
@get:Bindable
|
||||
open val isChecked get() = false
|
||||
@get:Bindable
|
||||
var isEnabled = true
|
||||
set(value) = set(value, field, { field = it }, BR.enabled, BR.description)
|
||||
|
||||
open fun onToggle(view: View, handler: Handler, checked: Boolean) {}
|
||||
open fun onPressed(view: View, handler: Handler) {
|
||||
handler.onItemPressed(view, this)
|
||||
handler.onItemPressed(view, this) {
|
||||
handler.onItemAction(view, this)
|
||||
}
|
||||
}
|
||||
open fun refresh() {}
|
||||
|
||||
interface Handler {
|
||||
fun onItemPressed(view: View, item: BaseSettingsItem, andThen: () -> Unit = {})
|
||||
fun onItemAction(view: View, item: BaseSettingsItem)
|
||||
}
|
||||
// Only for toggle
|
||||
open val showSwitch get() = false
|
||||
@get:Bindable
|
||||
open val isChecked get() = false
|
||||
fun onToggle(view: View, handler: Handler, checked: Boolean) =
|
||||
set(checked, isChecked, { onPressed(view, handler) })
|
||||
|
||||
abstract class Value<T> : BaseSettingsItem() {
|
||||
|
||||
@@ -54,9 +59,6 @@ sealed class BaseSettingsItem : ObservableRvItem() {
|
||||
override val showSwitch get() = true
|
||||
override val isChecked get() = value
|
||||
|
||||
override fun onToggle(view: View, handler: Handler, checked: Boolean) =
|
||||
set(checked, value, { onPressed(view, handler) })
|
||||
|
||||
override fun onPressed(view: View, handler: Handler) {
|
||||
// Make sure the checked state is synced
|
||||
notifyPropertyChanged(BR.checked)
|
||||
@@ -140,5 +142,4 @@ sealed class BaseSettingsItem : ObservableRvItem() {
|
||||
abstract class Section : BaseSettingsItem() {
|
||||
override val layoutRes = R.layout.item_settings_section
|
||||
}
|
||||
|
||||
}
|
@@ -9,6 +9,7 @@ import com.topjohnwu.magisk.databinding.FragmentSettingsMd2Binding
|
||||
import rikka.recyclerview.addEdgeSpacing
|
||||
import rikka.recyclerview.addItemSpacing
|
||||
import rikka.recyclerview.fixEdgeEffect
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class SettingsFragment : BaseFragment<FragmentSettingsMd2Binding>() {
|
||||
|
||||
@@ -19,7 +20,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsMd2Binding>() {
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
activity?.title = resources.getString(R.string.settings)
|
||||
activity?.title = resources.getString(CoreR.string.settings)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
@@ -7,83 +7,70 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.databinding.Bindable
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.BuildConfig
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.core.ktx.activity
|
||||
import com.topjohnwu.magisk.core.tasks.AppMigration
|
||||
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
import com.topjohnwu.magisk.core.utils.availableLocales
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import com.topjohnwu.magisk.databinding.DialogSettingsAppNameBinding
|
||||
import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding
|
||||
import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.ktx.activity
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.TextHolder
|
||||
import com.topjohnwu.magisk.utils.asText
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
// --- Customization
|
||||
|
||||
object Customization : BaseSettingsItem.Section() {
|
||||
override val title = R.string.settings_customization.asText()
|
||||
override val title = CoreR.string.settings_customization.asText()
|
||||
}
|
||||
|
||||
object Language : BaseSettingsItem.Selector() {
|
||||
private val names: Array<String> get() = LocaleSetting.available.names
|
||||
private val tags: Array<String> get() = LocaleSetting.available.tags
|
||||
|
||||
override var value
|
||||
get() = index
|
||||
get() = tags.indexOf(Config.locale)
|
||||
set(value) {
|
||||
index = value
|
||||
Config.locale = entryValues[value]
|
||||
Config.locale = tags[value]
|
||||
}
|
||||
|
||||
override val title = R.string.language.asText()
|
||||
override val title = CoreR.string.language.asText()
|
||||
|
||||
private var entries = emptyArray<String>()
|
||||
private var entryValues = emptyArray<String>()
|
||||
private var index = -1
|
||||
override fun entries(res: Resources) = names
|
||||
override fun descriptions(res: Resources) = names
|
||||
}
|
||||
|
||||
override fun entries(res: Resources) = entries
|
||||
override fun descriptions(res: Resources) = entries
|
||||
|
||||
override fun onPressed(view: View, handler: Handler) {
|
||||
if (entries.isNotEmpty())
|
||||
super.onPressed(view, handler)
|
||||
}
|
||||
|
||||
suspend fun loadLanguages(scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
availableLocales().let { (names, values) ->
|
||||
entries = names
|
||||
entryValues = values
|
||||
val selectedLocale = currentLocale.getDisplayName(currentLocale)
|
||||
index = names.indexOfFirst { it == selectedLocale }.let { if (it == -1) 0 else it }
|
||||
notifyPropertyChanged(BR.description)
|
||||
}
|
||||
object LanguageSystem : BaseSettingsItem.Blank() {
|
||||
override val title = CoreR.string.language.asText()
|
||||
override val description: TextHolder
|
||||
get() {
|
||||
val locale = LocaleSetting.instance.appLocale
|
||||
return locale?.getDisplayName(locale)?.asText() ?: CoreR.string.system_default.asText()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Theme : BaseSettingsItem.Blank() {
|
||||
override val icon = R.drawable.ic_paint
|
||||
override val title = R.string.section_theme.asText()
|
||||
override val title = CoreR.string.section_theme.asText()
|
||||
}
|
||||
|
||||
// --- App
|
||||
|
||||
object AppSettings : BaseSettingsItem.Section() {
|
||||
override val title = R.string.home_app_title.asText()
|
||||
override val title = CoreR.string.home_app_title.asText()
|
||||
}
|
||||
|
||||
object Hide : BaseSettingsItem.Input() {
|
||||
override val title = R.string.settings_hide_app_title.asText()
|
||||
override val description = R.string.settings_hide_app_summary.asText()
|
||||
override val title = CoreR.string.settings_hide_app_title.asText()
|
||||
override val description = CoreR.string.settings_hide_app_summary.asText()
|
||||
override var value = ""
|
||||
|
||||
override val inputResult
|
||||
@@ -94,7 +81,7 @@ object Hide : BaseSettingsItem.Input() {
|
||||
set(value) = set(value, field, { field = it }, BR.result, BR.error)
|
||||
|
||||
val maxLength
|
||||
get() = HideAPK.MAX_LABEL_LENGTH
|
||||
get() = AppMigration.MAX_LABEL_LENGTH
|
||||
|
||||
@get:Bindable
|
||||
val isError
|
||||
@@ -105,14 +92,14 @@ object Hide : BaseSettingsItem.Input() {
|
||||
}
|
||||
|
||||
object Restore : BaseSettingsItem.Blank() {
|
||||
override val title = R.string.settings_restore_app_title.asText()
|
||||
override val description = R.string.settings_restore_app_summary.asText()
|
||||
override val title = CoreR.string.settings_restore_app_title.asText()
|
||||
override val description = CoreR.string.settings_restore_app_summary.asText()
|
||||
|
||||
override fun onPressed(view: View, handler: Handler) {
|
||||
handler.onItemPressed(view, this) {
|
||||
MagiskDialog(view.activity).apply {
|
||||
setTitle(R.string.settings_restore_app_title)
|
||||
setMessage(R.string.restore_app_confirmation)
|
||||
setTitle(CoreR.string.settings_restore_app_title)
|
||||
setMessage(CoreR.string.restore_app_confirmation)
|
||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
text = android.R.string.ok
|
||||
onClick {
|
||||
@@ -130,8 +117,8 @@ object Restore : BaseSettingsItem.Blank() {
|
||||
}
|
||||
|
||||
object AddShortcut : BaseSettingsItem.Blank() {
|
||||
override val title = R.string.add_shortcut_title.asText()
|
||||
override val description = R.string.setting_add_shortcut_summary.asText()
|
||||
override val title = CoreR.string.add_shortcut_title.asText()
|
||||
override val description = CoreR.string.setting_add_shortcut_summary.asText()
|
||||
}
|
||||
|
||||
object DownloadPath : BaseSettingsItem.Input() {
|
||||
@@ -142,7 +129,7 @@ object DownloadPath : BaseSettingsItem.Input() {
|
||||
notifyPropertyChanged(BR.description)
|
||||
}
|
||||
|
||||
override val title = R.string.settings_download_path_title.asText()
|
||||
override val title = CoreR.string.settings_download_path_title.asText()
|
||||
override val description get() = MediaStoreUtils.fullPath(value).asText()
|
||||
|
||||
override var inputResult: String = value
|
||||
@@ -163,9 +150,9 @@ object UpdateChannel : BaseSettingsItem.Selector() {
|
||||
Info.remote = Info.EMPTY_REMOTE
|
||||
}
|
||||
|
||||
override val title = R.string.settings_update_channel_title.asText()
|
||||
override val title = CoreR.string.settings_update_channel_title.asText()
|
||||
|
||||
override val entryRes = R.array.update_channel
|
||||
override val entryRes = CoreR.array.update_channel
|
||||
override fun entries(res: Resources): Array<String> {
|
||||
return super.entries(res).let {
|
||||
if (!Const.APP_IS_CANARY && !BuildConfig.DEBUG)
|
||||
@@ -176,7 +163,7 @@ object UpdateChannel : BaseSettingsItem.Selector() {
|
||||
}
|
||||
|
||||
object UpdateChannelUrl : BaseSettingsItem.Input() {
|
||||
override val title = R.string.settings_update_custom.asText()
|
||||
override val title = CoreR.string.settings_update_custom.asText()
|
||||
override val description get() = value.asText()
|
||||
override var value
|
||||
get() = Config.customChannelUrl
|
||||
@@ -198,56 +185,51 @@ object UpdateChannelUrl : BaseSettingsItem.Input() {
|
||||
}
|
||||
|
||||
object UpdateChecker : BaseSettingsItem.Toggle() {
|
||||
override val title = R.string.settings_check_update_title.asText()
|
||||
override val description = R.string.settings_check_update_summary.asText()
|
||||
override val title = CoreR.string.settings_check_update_title.asText()
|
||||
override val description = CoreR.string.settings_check_update_summary.asText()
|
||||
override var value by Config::checkUpdate
|
||||
}
|
||||
|
||||
object DoHToggle : BaseSettingsItem.Toggle() {
|
||||
override val title = R.string.settings_doh_title.asText()
|
||||
override val description = R.string.settings_doh_description.asText()
|
||||
override val title = CoreR.string.settings_doh_title.asText()
|
||||
override val description = CoreR.string.settings_doh_description.asText()
|
||||
override var value by Config::doh
|
||||
}
|
||||
|
||||
object SystemlessHosts : BaseSettingsItem.Blank() {
|
||||
override val title = R.string.settings_hosts_title.asText()
|
||||
override val description = R.string.settings_hosts_summary.asText()
|
||||
override val title = CoreR.string.settings_hosts_title.asText()
|
||||
override val description = CoreR.string.settings_hosts_summary.asText()
|
||||
}
|
||||
|
||||
object RandNameToggle : BaseSettingsItem.Toggle() {
|
||||
override val title = CoreR.string.settings_random_name_title.asText()
|
||||
override val description = CoreR.string.settings_random_name_description.asText()
|
||||
override var value by Config::randName
|
||||
}
|
||||
|
||||
// --- Magisk
|
||||
|
||||
object Magisk : BaseSettingsItem.Section() {
|
||||
override val title = R.string.magisk.asText()
|
||||
override val title = CoreR.string.magisk.asText()
|
||||
}
|
||||
|
||||
object Zygisk : BaseSettingsItem.Toggle() {
|
||||
override val title = R.string.zygisk.asText()
|
||||
override val title = CoreR.string.zygisk.asText()
|
||||
override val description get() =
|
||||
if (mismatch) R.string.reboot_apply_change.asText()
|
||||
else R.string.settings_zygisk_summary.asText()
|
||||
if (mismatch) CoreR.string.reboot_apply_change.asText()
|
||||
else CoreR.string.settings_zygisk_summary.asText()
|
||||
override var value
|
||||
get() = Config.zygisk
|
||||
set(value) {
|
||||
Config.zygisk = value
|
||||
DenyList.isEnabled = value
|
||||
DenyListConfig.isEnabled = value
|
||||
notifyPropertyChanged(BR.description)
|
||||
DenyList.notifyPropertyChanged(BR.description)
|
||||
}
|
||||
val mismatch get() = value != Info.isZygiskEnabled
|
||||
}
|
||||
|
||||
object DenyList : BaseSettingsItem.Toggle() {
|
||||
override val title = R.string.settings_denylist_title.asText()
|
||||
override val description get() =
|
||||
if (isEnabled) {
|
||||
if (Zygisk.mismatch)
|
||||
R.string.reboot_apply_change.asText()
|
||||
else
|
||||
R.string.settings_denylist_summary.asText()
|
||||
} else {
|
||||
R.string.settings_denylist_error.asText(R.string.zygisk.asText())
|
||||
}
|
||||
override val title = CoreR.string.settings_denylist_title.asText()
|
||||
override val description get() = CoreR.string.settings_denylist_summary.asText()
|
||||
|
||||
override var value = Config.denyList
|
||||
set(value) {
|
||||
@@ -262,57 +244,48 @@ object DenyList : BaseSettingsItem.Toggle() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun refresh() {
|
||||
isEnabled = Zygisk.value
|
||||
}
|
||||
}
|
||||
|
||||
object DenyListConfig : BaseSettingsItem.Blank() {
|
||||
override val title = R.string.settings_denylist_config_title.asText()
|
||||
override val description = R.string.settings_denylist_config_summary.asText()
|
||||
override fun refresh() {
|
||||
isEnabled = Zygisk.value
|
||||
}
|
||||
override val title = CoreR.string.settings_denylist_config_title.asText()
|
||||
override val description = CoreR.string.settings_denylist_config_summary.asText()
|
||||
}
|
||||
|
||||
// --- Superuser
|
||||
|
||||
object Tapjack : BaseSettingsItem.Toggle() {
|
||||
override val title = R.string.settings_su_tapjack_title.asText()
|
||||
override val description = R.string.settings_su_tapjack_summary.asText()
|
||||
override val title = CoreR.string.settings_su_tapjack_title.asText()
|
||||
override val description = CoreR.string.settings_su_tapjack_summary.asText()
|
||||
override var value by Config::suTapjack
|
||||
}
|
||||
|
||||
object Biometrics : BaseSettingsItem.Toggle() {
|
||||
override val title = R.string.settings_su_biometric_title.asText()
|
||||
override var description = R.string.settings_su_biometric_summary.asText()
|
||||
override var value by Config::suBiometric
|
||||
object Authentication : BaseSettingsItem.Toggle() {
|
||||
override val title = CoreR.string.settings_su_auth_title.asText()
|
||||
override var description = CoreR.string.settings_su_auth_summary.asText()
|
||||
override var value by Config::suAuth
|
||||
|
||||
override fun refresh() {
|
||||
isEnabled = BiometricHelper.isSupported
|
||||
isEnabled = Info.isDeviceSecure
|
||||
if (!isEnabled) {
|
||||
value = false
|
||||
description = R.string.no_biometric.asText()
|
||||
notifyPropertyChanged(BR.checked)
|
||||
description = CoreR.string.settings_su_auth_insecure.asText()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Superuser : BaseSettingsItem.Section() {
|
||||
override val title = R.string.superuser.asText()
|
||||
override val title = CoreR.string.superuser.asText()
|
||||
}
|
||||
|
||||
object AccessMode : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.superuser_access.asText()
|
||||
override val entryRes = R.array.su_access
|
||||
override val title = CoreR.string.superuser_access.asText()
|
||||
override val entryRes = CoreR.array.su_access
|
||||
override var value by Config::rootMode
|
||||
}
|
||||
|
||||
object MultiuserMode : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.multiuser_mode.asText()
|
||||
override val entryRes = R.array.multiuser_mode
|
||||
override val descriptionRes = R.array.multiuser_summary
|
||||
override val title = CoreR.string.multiuser_mode.asText()
|
||||
override val entryRes = CoreR.array.multiuser_mode
|
||||
override val descriptionRes = CoreR.array.multiuser_summary
|
||||
override var value by Config::suMultiuserMode
|
||||
|
||||
override fun refresh() {
|
||||
@@ -321,21 +294,21 @@ object MultiuserMode : BaseSettingsItem.Selector() {
|
||||
}
|
||||
|
||||
object MountNamespaceMode : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.mount_namespace_mode.asText()
|
||||
override val entryRes = R.array.namespace
|
||||
override val descriptionRes = R.array.namespace_summary
|
||||
override val title = CoreR.string.mount_namespace_mode.asText()
|
||||
override val entryRes = CoreR.array.namespace
|
||||
override val descriptionRes = CoreR.array.namespace_summary
|
||||
override var value by Config::suMntNamespaceMode
|
||||
}
|
||||
|
||||
object AutomaticResponse : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.auto_response.asText()
|
||||
override val entryRes = R.array.auto_response
|
||||
override val title = CoreR.string.auto_response.asText()
|
||||
override val entryRes = CoreR.array.auto_response
|
||||
override var value by Config::suAutoResponse
|
||||
}
|
||||
|
||||
object RequestTimeout : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.request_timeout.asText()
|
||||
override val entryRes = R.array.request_timeout
|
||||
override val title = CoreR.string.request_timeout.asText()
|
||||
override val entryRes = CoreR.array.request_timeout
|
||||
|
||||
private val entryValues = listOf(10, 15, 20, 30, 45, 60)
|
||||
override var value = entryValues.indexOfFirst { it == Config.suDefaultTimeout }
|
||||
@@ -346,17 +319,17 @@ object RequestTimeout : BaseSettingsItem.Selector() {
|
||||
}
|
||||
|
||||
object SUNotification : BaseSettingsItem.Selector() {
|
||||
override val title = R.string.superuser_notification.asText()
|
||||
override val entryRes = R.array.su_notification
|
||||
override val title = CoreR.string.superuser_notification.asText()
|
||||
override val entryRes = CoreR.array.su_notification
|
||||
override var value by Config::suNotification
|
||||
}
|
||||
|
||||
object Reauthenticate : BaseSettingsItem.Toggle() {
|
||||
override val title = R.string.settings_su_reauth_title.asText()
|
||||
override val description = R.string.settings_su_reauth_summary.asText()
|
||||
override val title = CoreR.string.settings_su_reauth_title.asText()
|
||||
override val description = CoreR.string.settings_su_reauth_summary.asText()
|
||||
override var value by Config::suReAuth
|
||||
|
||||
override fun refresh() {
|
||||
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Utils.showSuperUser()
|
||||
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Info.showSuperUser
|
||||
}
|
||||
}
|
@@ -1,25 +1,30 @@
|
||||
package com.topjohnwu.magisk.ui.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||
import com.topjohnwu.magisk.core.AppContext
|
||||
import com.topjohnwu.magisk.core.BuildConfig
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.core.ktx.activity
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.tasks.AppMigration
|
||||
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
||||
import com.topjohnwu.magisk.databinding.bindExtra
|
||||
import com.topjohnwu.magisk.events.AddHomeIconEvent
|
||||
import com.topjohnwu.magisk.events.BiometricEvent
|
||||
import com.topjohnwu.magisk.events.AuthEvent
|
||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.ktx.activity
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -30,20 +35,14 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
||||
it.put(BR.handler, this)
|
||||
}
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
Language.loadLanguages(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createItems(): List<BaseSettingsItem> {
|
||||
val context = AppContext
|
||||
val hidden = context.packageName != BuildConfig.APPLICATION_ID
|
||||
val hidden = context.packageName != BuildConfig.APP_PACKAGE_NAME
|
||||
|
||||
// Customization
|
||||
val list = mutableListOf(
|
||||
Customization,
|
||||
Theme, Language
|
||||
Theme, if (LocaleSetting.useLocaleManager) LanguageSystem else Language
|
||||
)
|
||||
if (isRunningAsStub && ShortcutManagerCompat.isRequestPinShortcutSupported(context))
|
||||
list.add(AddShortcut)
|
||||
@@ -51,7 +50,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
||||
// Manager
|
||||
list.addAll(listOf(
|
||||
AppSettings,
|
||||
UpdateChannel, UpdateChannelUrl, DoHToggle, UpdateChecker, DownloadPath
|
||||
UpdateChannel, UpdateChannelUrl, DoHToggle, UpdateChecker, DownloadPath, RandNameToggle
|
||||
))
|
||||
if (Info.env.isActive && Const.USER_ID == 0) {
|
||||
if (hidden) list.add(Restore) else list.add(Hide)
|
||||
@@ -69,10 +68,10 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
||||
}
|
||||
|
||||
// Superuser
|
||||
if (Utils.showSuperUser()) {
|
||||
if (Info.showSuperUser) {
|
||||
list.addAll(listOf(
|
||||
Superuser,
|
||||
Tapjack, Biometrics, AccessMode, MultiuserMode, MountNamespaceMode,
|
||||
Tapjack, Authentication, AccessMode, MultiuserMode, MountNamespaceMode,
|
||||
AutomaticResponse, RequestTimeout, SUNotification
|
||||
))
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
@@ -88,30 +87,37 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
||||
return list
|
||||
}
|
||||
|
||||
override fun onItemPressed(view: View, item: BaseSettingsItem, andThen: () -> Unit) {
|
||||
override fun onItemPressed(view: View, item: BaseSettingsItem, doAction: () -> Unit) {
|
||||
when (item) {
|
||||
DownloadPath -> withExternalRW(andThen)
|
||||
UpdateChecker -> withPostNotificationPermission(andThen)
|
||||
Biometrics -> authenticate(andThen)
|
||||
Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate()
|
||||
DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate()
|
||||
SystemlessHosts -> createHosts()
|
||||
Hide, Restore -> withInstallPermission(andThen)
|
||||
AddShortcut -> AddHomeIconEvent().publish()
|
||||
else -> andThen()
|
||||
DownloadPath -> withExternalRW(doAction)
|
||||
UpdateChecker -> withPostNotificationPermission(doAction)
|
||||
Authentication -> AuthEvent(doAction).publish()
|
||||
Hide, Restore -> withInstallPermission(doAction)
|
||||
else -> doAction()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemAction(view: View, item: BaseSettingsItem) {
|
||||
when (item) {
|
||||
Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate()
|
||||
LanguageSystem -> launchAppLocaleSettings(view.activity)
|
||||
AddShortcut -> AddHomeIconEvent().publish()
|
||||
SystemlessHosts -> createHosts()
|
||||
DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate()
|
||||
UpdateChannel -> openUrlIfNecessary(view)
|
||||
is Hide -> viewModelScope.launch { HideAPK.hide(view.activity, item.value) }
|
||||
Restore -> viewModelScope.launch { HideAPK.restore(view.activity) }
|
||||
is Hide -> viewModelScope.launch { AppMigration.hide(view.activity, item.value) }
|
||||
Restore -> viewModelScope.launch { AppMigration.restore(view.activity) }
|
||||
Zygisk -> if (Zygisk.mismatch) SnackbarEvent(R.string.reboot_apply_change).publish()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchAppLocaleSettings(activity: Activity) {
|
||||
val intent = Intent(Settings.ACTION_APP_LOCALE_SETTINGS)
|
||||
intent.data = Uri.fromParts("package", activity.packageName, null)
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
|
||||
private fun openUrlIfNecessary(view: View) {
|
||||
UpdateChannelUrl.refresh()
|
||||
if (UpdateChannelUrl.isEnabled && UpdateChannelUrl.value.isBlank()) {
|
||||
@@ -119,16 +125,9 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
private fun authenticate(callback: () -> Unit) {
|
||||
BiometricEvent {
|
||||
// allow the change on success
|
||||
onSuccess { callback() }
|
||||
}.publish()
|
||||
}
|
||||
|
||||
private fun createHosts() {
|
||||
Shell.cmd("add_hosts_module").submit {
|
||||
Utils.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
|
||||
AppContext.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
}
|
@@ -73,6 +73,8 @@ class PolicyRvItem(
|
||||
viewModel.deletePressed(this)
|
||||
}
|
||||
|
||||
override fun itemSameAs(other: PolicyRvItem) = item.uid == other.item.uid
|
||||
override fun itemSameAs(other: PolicyRvItem) = packageName == other.packageName
|
||||
|
||||
override fun contentSameAs(other: PolicyRvItem) = item.policy == other.item.policy
|
||||
|
||||
}
|
@@ -9,6 +9,7 @@ import com.topjohnwu.magisk.databinding.FragmentSuperuserMd2Binding
|
||||
import rikka.recyclerview.addEdgeSpacing
|
||||
import rikka.recyclerview.addItemSpacing
|
||||
import rikka.recyclerview.fixEdgeEffect
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class SuperuserFragment : BaseFragment<FragmentSuperuserMd2Binding>() {
|
||||
|
||||
@@ -17,7 +18,7 @@ class SuperuserFragment : BaseFragment<FragmentSuperuserMd2Binding>() {
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
activity?.title = resources.getString(R.string.superuser)
|
||||
activity?.title = resources.getString(CoreR.string.superuser)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
@@ -8,24 +8,28 @@ import androidx.databinding.Bindable
|
||||
import androidx.databinding.ObservableArrayList
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||
import com.topjohnwu.magisk.core.AppContext
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
||||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import com.topjohnwu.magisk.core.ktx.getLabel
|
||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import com.topjohnwu.magisk.databinding.*
|
||||
import com.topjohnwu.magisk.databinding.MergeObservableList
|
||||
import com.topjohnwu.magisk.databinding.RvItem
|
||||
import com.topjohnwu.magisk.databinding.bindExtra
|
||||
import com.topjohnwu.magisk.databinding.diffList
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.dialog.SuperuserRevokeDialog
|
||||
import com.topjohnwu.magisk.events.BiometricEvent
|
||||
import com.topjohnwu.magisk.events.AuthEvent
|
||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.ktx.getLabel
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.asText
|
||||
import com.topjohnwu.magisk.view.TextItem
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.Locale
|
||||
|
||||
class SuperuserViewModel(
|
||||
private val db: PolicyDao
|
||||
@@ -34,7 +38,7 @@ class SuperuserViewModel(
|
||||
private val itemNoData = TextItem(R.string.superuser_policy_none)
|
||||
|
||||
private val itemsHelpers = ObservableArrayList<TextItem>()
|
||||
private val itemsPolicies = DiffObservableList<PolicyRvItem>()
|
||||
private val itemsPolicies = diffList<PolicyRvItem>()
|
||||
|
||||
val items = MergeObservableList<RvItem>()
|
||||
.insertList(itemsHelpers)
|
||||
@@ -49,7 +53,7 @@ class SuperuserViewModel(
|
||||
|
||||
@SuppressLint("InlinedApi")
|
||||
override suspend fun doLoadWork() {
|
||||
if (!Utils.showSuperUser()) {
|
||||
if (!Info.showSuperUser) {
|
||||
loading = false
|
||||
return
|
||||
}
|
||||
@@ -88,7 +92,7 @@ class SuperuserViewModel(
|
||||
policies.addAll(map)
|
||||
}
|
||||
policies.sortWith(compareBy(
|
||||
{ it.appName.lowercase(currentLocale) },
|
||||
{ it.appName.lowercase(Locale.ROOT) },
|
||||
{ it.packageName }
|
||||
))
|
||||
itemsPolicies.update(policies)
|
||||
@@ -105,16 +109,16 @@ class SuperuserViewModel(
|
||||
fun deletePressed(item: PolicyRvItem) {
|
||||
fun updateState() = viewModelScope.launch {
|
||||
db.delete(item.item.uid)
|
||||
itemsPolicies.removeAll { it.itemSameAs(item) }
|
||||
if (itemsPolicies.isEmpty() && itemsHelpers.isEmpty()) {
|
||||
val list = ArrayList(itemsPolicies)
|
||||
list.removeAll { it.item.uid == item.item.uid }
|
||||
itemsPolicies.update(list)
|
||||
if (list.isEmpty() && itemsHelpers.isEmpty()) {
|
||||
itemsHelpers.add(itemNoData)
|
||||
}
|
||||
}
|
||||
|
||||
if (BiometricHelper.isEnabled) {
|
||||
BiometricEvent {
|
||||
onSuccess { updateState() }
|
||||
}.publish()
|
||||
if (Config.suAuth) {
|
||||
AuthEvent { updateState() }.publish()
|
||||
} else {
|
||||
SuperuserRevokeDialog(item.title) { updateState() }.show()
|
||||
}
|
||||
@@ -153,24 +157,21 @@ class SuperuserViewModel(
|
||||
}
|
||||
|
||||
fun togglePolicy(item: PolicyRvItem, enable: Boolean) {
|
||||
val items = itemsPolicies.filter { it.item.uid == item.item.uid }
|
||||
fun updateState() {
|
||||
viewModelScope.launch {
|
||||
val res = if (enable) R.string.su_snack_grant else R.string.su_snack_deny
|
||||
item.item.policy = if (enable) SuPolicy.ALLOW else SuPolicy.DENY
|
||||
db.update(item.item)
|
||||
itemsPolicies.forEach {
|
||||
if (it.item.uid == item.item.uid) {
|
||||
it.notifyPropertyChanged(BR.enabled)
|
||||
}
|
||||
items.forEach {
|
||||
it.notifyPropertyChanged(BR.enabled)
|
||||
}
|
||||
SnackbarEvent(res.asText(item.appName)).publish()
|
||||
}
|
||||
}
|
||||
|
||||
if (BiometricHelper.isEnabled) {
|
||||
BiometricEvent {
|
||||
onSuccess { updateState() }
|
||||
}.publish()
|
||||
if (Config.suAuth) {
|
||||
AuthEvent { updateState() }.publish()
|
||||
} else {
|
||||
updateState()
|
||||
}
|
@@ -11,6 +11,7 @@ import androidx.lifecycle.lifecycleScope
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.UIActivity
|
||||
import com.topjohnwu.magisk.arch.viewModel
|
||||
import com.topjohnwu.magisk.core.base.UntrackedActivity
|
||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler
|
||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler.REQUEST
|
||||
import com.topjohnwu.magisk.databinding.ActivityRequestBinding
|
||||
@@ -19,7 +20,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
open class SuRequestActivity : UIActivity<ActivityRequestBinding>() {
|
||||
open class SuRequestActivity : UIActivity<ActivityRequestBinding>(), UntrackedActivity {
|
||||
|
||||
override val layoutRes: Int = R.layout.activity_request
|
||||
override val viewModel: SuRequestViewModel by viewModel()
|
@@ -17,22 +17,22 @@ import android.widget.Toast
|
||||
import androidx.databinding.Bindable
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||
import com.topjohnwu.magisk.core.AppContext
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.R
|
||||
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
||||
import com.topjohnwu.magisk.core.di.AppContext
|
||||
import com.topjohnwu.magisk.core.ktx.getLabel
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.ALLOW
|
||||
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.DENY
|
||||
import com.topjohnwu.magisk.core.su.SuRequestHandler
|
||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.events.BiometricEvent
|
||||
import com.topjohnwu.magisk.events.AuthEvent
|
||||
import com.topjohnwu.magisk.events.DieEvent
|
||||
import com.topjohnwu.magisk.events.ShowUIEvent
|
||||
import com.topjohnwu.magisk.ktx.getLabel
|
||||
import com.topjohnwu.magisk.utils.TextHolder
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.TimeUnit.SECONDS
|
||||
|
||||
@@ -62,7 +62,7 @@ class SuRequestViewModel(
|
||||
if (event.flags and MotionEvent.FLAG_WINDOW_IS_OBSCURED != 0
|
||||
|| event.flags and MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED != 0) {
|
||||
if (event.action == MotionEvent.ACTION_UP) {
|
||||
Utils.toast(R.string.touch_filtered_warning, Toast.LENGTH_SHORT)
|
||||
AppContext.toast(R.string.touch_filtered_warning, Toast.LENGTH_SHORT)
|
||||
}
|
||||
return@OnTouchListener Config.suTapjack
|
||||
}
|
||||
@@ -70,17 +70,14 @@ class SuRequestViewModel(
|
||||
}
|
||||
|
||||
private val handler = SuRequestHandler(AppContext.packageManager, policyDB)
|
||||
private lateinit var timer: CountDownTimer
|
||||
private val millis = SECONDS.toMillis(Config.suDefaultTimeout.toLong())
|
||||
private var timer = SuTimer(millis, 1000)
|
||||
private var initialized = false
|
||||
|
||||
fun grantPressed() {
|
||||
cancelTimer()
|
||||
if (BiometricHelper.isEnabled) {
|
||||
BiometricEvent {
|
||||
onSuccess {
|
||||
respond(ALLOW)
|
||||
}
|
||||
}.publish()
|
||||
if (Config.suAuth) {
|
||||
AuthEvent { respond(ALLOW) }.publish()
|
||||
} else {
|
||||
respond(ALLOW)
|
||||
}
|
||||
@@ -96,7 +93,7 @@ class SuRequestViewModel(
|
||||
}
|
||||
|
||||
fun handleRequest(intent: Intent) {
|
||||
viewModelScope.launch {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
if (handler.start(intent))
|
||||
showDialog()
|
||||
else
|
||||
@@ -125,8 +122,7 @@ class SuRequestViewModel(
|
||||
selectedItemPosition = timeoutPrefs.getInt(packageName, 0)
|
||||
|
||||
// Set timer
|
||||
val millis = SECONDS.toMillis(Config.suDefaultTimeout.toLong())
|
||||
timer = SuTimer(millis, 1000).apply { start() }
|
||||
timer.start()
|
||||
|
||||
// Actually show the UI
|
||||
ShowUIEvent(if (Config.suTapjack) EmptyAccessibilityDelegate else null).publish()
|
@@ -12,6 +12,7 @@ import com.topjohnwu.magisk.arch.BaseFragment
|
||||
import com.topjohnwu.magisk.arch.viewModel
|
||||
import com.topjohnwu.magisk.databinding.FragmentThemeMd2Binding
|
||||
import com.topjohnwu.magisk.databinding.ItemThemeBindingImpl
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class ThemeFragment : BaseFragment<FragmentThemeMd2Binding>() {
|
||||
|
||||
@@ -61,7 +62,7 @@ class ThemeFragment : BaseFragment<FragmentThemeMd2Binding>() {
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
activity?.title = getString(R.string.section_theme)
|
||||
activity?.title = getString(CoreR.string.section_theme)
|
||||
}
|
||||
|
||||
}
|
@@ -14,7 +14,7 @@ import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||
import com.google.android.material.circularreveal.CircularRevealCompat
|
||||
import com.google.android.material.circularreveal.CircularRevealWidget
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
||||
import kotlin.math.hypot
|
||||
|
||||
object MotionRevealHelper {
|
||||
@@ -63,7 +63,9 @@ object MotionRevealHelper {
|
||||
it.interpolator = FastOutSlowInInterpolator()
|
||||
it.addListener(onStart = { show() }, onEnd = { if (revealInfo.radius != 0f) hide() })
|
||||
|
||||
val rtlMod = if (currentLocale.layoutDirection == View.LAYOUT_DIRECTION_RTL) 1f else -1f
|
||||
val rtlMod =
|
||||
if (LocaleSetting.instance.currentLocale.layoutDirection == View.LAYOUT_DIRECTION_RTL)
|
||||
1f else -1f
|
||||
val maxX = revealInfo.centerX - marginEnd - measuredWidth / 2f
|
||||
val targetX = if (revealInfo.radius == 0f) 0f else maxX * rtlMod
|
||||
val moveX = ObjectAnimator.ofFloat(this, View.TRANSLATION_X, targetX)
|
@@ -21,7 +21,7 @@ import com.google.android.material.color.MaterialColors
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.arch.UIActivity
|
||||
import com.topjohnwu.magisk.databinding.DialogMagiskBaseBinding
|
||||
import com.topjohnwu.magisk.databinding.DiffItem
|
||||
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||
@@ -42,7 +42,7 @@ class MagiskDialog(
|
||||
DialogMagiskBaseBinding.inflate(LayoutInflater.from(context))
|
||||
private val data = Data()
|
||||
|
||||
val activity: BaseActivity get() = ownerActivity as BaseActivity
|
||||
val activity: UIActivity<*> get() = ownerActivity as UIActivity<*>
|
||||
|
||||
init {
|
||||
binding.setVariable(BR.data, data)
|
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.view
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.databinding.DiffItem
|
||||
import com.topjohnwu.magisk.databinding.RvItem
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
sealed class TappableHeadlineItem : RvItem(), DiffItem<TappableHeadlineItem> {
|
||||
|
||||
@@ -22,7 +23,7 @@ sealed class TappableHeadlineItem : RvItem(), DiffItem<TappableHeadlineItem> {
|
||||
// --- objects
|
||||
|
||||
object ThemeMode : TappableHeadlineItem() {
|
||||
override val title = R.string.settings_dark_mode_title
|
||||
override val title = CoreR.string.settings_dark_mode_title
|
||||
override val icon = R.drawable.ic_day_night
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 20 8 L 20 8 L 17.19 8 C 16.74 7.22 16.12 6.55 15.37 6.04 L 17 4.41 L 15.59 3 L 13.42 5.17 C 12.96 5.06 12.49 5 12 5 C 11.51 5 11.04 5.06 10.59 5.17 L 8.41 3 L 7 4.41 L 8.62 6.04 C 7.88 6.55 7.26 7.22 6.81 8 L 4 8 L 4 10 L 6.09 10 C 6.04 10.33 6 10.66 6 11 L 6 12 L 4 12 L 4 14 L 6 14 L 6 15 C 6 15.34 6.04 15.67 6.09 16 L 4 16 L 4 18 L 6.81 18 C 7.85 19.79 9.78 21 12 21 C 14.22 21 16.15 19.79 17.19 18 L 20 18 L 20 16 L 17.91 16 C 17.96 15.67 18 15.34 18 15 L 18 14 L 20 14 L 20 12 L 18 12 L 18 11 C 18 10.66 17.96 10.33 17.91 10 L 20 10 L 20 8 M 14 16 C 14 15.43 14 14.859 14 14.289 L 14 14 C 13.869 14 13.739 14 13.608 14 C 12.405 14 11.203 14 10 14 C 10 14.509 10 15.017 10 15.526 C 10 15.684 10 15.842 10 16 L 10.33 16 C 10.392 16 10.454 16 10.515 16 C 11.677 16 12.838 16 14 16 C 14 16 14 16 14 16 M 14 10 L 14 12 L 14 12 L 10 12 L 10 10 L 14 10 M 12 15 L 12 15 L 12 15 L 12 15 L 12 15 L 12 15"
|
||||
android:valueTo="M 20 8 L 18.595 8 L 17.19 8 C 16.74 7.2 16.12 6.5 15.37 6 L 17 4.41 L 15.59 3 L 13.42 5.17 C 12.96 5.06 12.5 5 12 5 C 11.5 5 11.05 5.06 10.59 5.17 L 8.41 3 L 7 4.41 L 8.62 6 C 7.87 6.5 7.26 7.21 6.81 8 L 4 8 L 4 10 L 6.09 10 C 6.03 10.33 6 10.66 6 11 L 6 12 L 4 12 L 4 14 L 6 14 L 6 15 C 6 15.34 6.03 15.67 6.09 16 L 4 16 L 4 18 L 6.81 18 C 8.47 20.87 12.14 21.84 15 20.18 C 15.91 19.66 16.67 18.9 17.19 18 L 20 18 L 20 16 L 17.91 16 C 17.97 15.67 18 15.34 18 15 L 18 14 L 20 14 L 20 12 L 18 12 L 18 11 C 18 10.66 17.97 10.33 17.91 10 L 20 10 L 20 8 M 14.828 17.828 C 15.578 17.079 16 16.06 16 15 L 16 11 C 16 9.94 15.578 8.921 14.828 8.172 C 14.079 7.422 13.06 7 12 7 C 10.94 7 9.921 7.422 9.172 8.172 C 8.422 8.921 8 9.94 8 11 L 8 15 C 8 16.06 8.422 17.079 9.172 17.828 C 9.921 18.578 10.94 19 12 19 C 13.06 19 14.079 18.578 14.828 17.828 M 14 10 L 14 11 L 14 12 L 10 12 L 10 10 L 14 10 M 10 14 L 14 14 L 14 16 L 10 16 L 10 14 L 10 14"
|
@@ -18,7 +18,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 20 8 L 18.595 8 L 17.19 8 C 16.74 7.2 16.12 6.5 15.37 6 L 17 4.41 L 15.59 3 L 13.42 5.17 C 12.96 5.06 12.5 5 12 5 C 11.5 5 11.05 5.06 10.59 5.17 L 8.41 3 L 7 4.41 L 8.62 6 C 7.87 6.5 7.26 7.21 6.81 8 L 4 8 L 4 10 L 6.09 10 C 6.03 10.33 6 10.66 6 11 L 6 12 L 4 12 L 4 14 L 6 14 L 6 15 C 6 15.34 6.03 15.67 6.09 16 L 4 16 L 4 18 L 6.81 18 C 8.47 20.87 12.14 21.84 15 20.18 C 15.91 19.66 16.67 18.9 17.19 18 L 20 18 L 20 16 L 17.91 16 C 17.97 15.67 18 15.34 18 15 L 18 14 L 20 14 L 20 12 L 18 12 L 18 11 C 18 10.66 17.97 10.33 17.91 10 L 20 10 L 20 8 M 14.828 17.828 C 15.578 17.079 16 16.06 16 15 L 16 11 C 16 9.94 15.578 8.921 14.828 8.172 C 14.079 7.422 13.06 7 12 7 C 10.94 7 9.921 7.422 9.172 8.172 C 8.422 8.921 8 9.94 8 11 L 8 15 C 8 16.06 8.422 17.079 9.172 17.828 C 9.921 18.578 10.94 19 12 19 C 13.06 19 14.079 18.578 14.828 17.828 M 14 10 L 14 11 L 14 12 L 10 12 L 10 10 L 14 10 M 10 14 L 14 14 L 14 16 L 10 16 L 10 14 L 10 14"
|
||||
android:valueTo="M 20 8 L 20 8 L 17.19 8 C 16.74 7.22 16.12 6.55 15.37 6.04 L 17 4.41 L 15.59 3 L 13.42 5.17 C 12.96 5.06 12.49 5 12 5 C 11.51 5 11.04 5.06 10.59 5.17 L 8.41 3 L 7 4.41 L 8.62 6.04 C 7.88 6.55 7.26 7.22 6.81 8 L 4 8 L 4 10 L 6.09 10 C 6.04 10.33 6 10.66 6 11 L 6 12 L 4 12 L 4 14 L 6 14 L 6 15 C 6 15.34 6.04 15.67 6.09 16 L 4 16 L 4 18 L 6.81 18 C 7.85 19.79 9.78 21 12 21 C 14.22 21 16.15 19.79 17.19 18 L 20 18 L 20 16 L 17.91 16 C 17.96 15.67 18 15.34 18 15 L 18 14 L 20 14 L 20 12 L 18 12 L 18 11 C 18 10.66 17.96 10.33 17.91 10 L 20 10 L 20 8 M 14 16 C 14 15.43 14 14.859 14 14.289 L 14 14 C 13.869 14 13.739 14 13.608 14 C 12.405 14 11.203 14 10 14 C 10 14.509 10 15.017 10 15.526 C 10 15.684 10 15.842 10 16 L 10.33 16 C 10.392 16 10.454 16 10.515 16 C 11.677 16 12.838 16 14 16 C 14 16 14 16 14 16 M 14 10 L 14 12 L 14 12 L 10 12 L 10 10 L 14 10 M 12 15 L 12 15 L 12 15 L 12 15 L 12 15 L 12 15"
|
@@ -17,7 +17,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="500"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 12 2 C 9.217 2 6.689 3.152 4.872 5.004 C 3.098 6.811 2 9.283 2 12 C 2 14.744 3.12 17.24 4.927 19.052 C 6.74 20.87 9.244 22 12 22 C 13.911 22 15.701 21.457 17.224 20.517 C 18.628 19.651 19.804 18.448 20.638 17.024 C 21.503 15.545 22 13.828 22 12 C 22 10.2 21.518 8.507 20.677 7.044 C 19.755 5.441 18.402 4.114 16.779 3.224 C 15.357 2.444 13.728 2 12 2 M 12 20 C 7.59 20 4 16.41 4 12 C 4 7.59 7.59 4 12 4 C 16.41 4 20 7.59 20 12 C 20 16.41 16.41 20 12 20 M 6 13 L 10 17 L 18 9 L 16.59 7.58 L 16.59 7.58 L 10 14.17 L 7.41 11.59 L 6 13"
|
||||
android:valueTo="M 12 2 C 9.349 2 6.804 3.054 4.929 4.929 C 3.054 6.804 2 9.349 2 12 C 2 14.651 3.054 17.196 4.929 19.071 C 6.804 20.946 9.349 22 12 22 C 13.755 22 15.48 21.538 17 20.66 C 18.52 19.783 19.783 18.52 20.66 17 C 21.538 15.48 22 13.755 22 12 C 22 10.245 21.538 8.52 20.66 7 C 19.783 5.48 18.52 4.217 17 3.34 C 15.48 2.462 13.755 2 12 2 M 12 20 C 7.59 20 4 16.41 4 12 C 4 7.59 7.59 4 12 4 C 16.41 4 20 7.59 20 12 C 20 16.41 16.41 20 12 20 M 7 13 L 7 13 L 17 13 L 17 11 L 17 11 L 7 11 L 7 11 L 7 11"
|
@@ -17,7 +17,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="500"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 12 2 C 9.349 2 6.804 3.054 4.929 4.929 C 3.054 6.804 2 9.349 2 12 C 2 14.651 3.054 17.196 4.929 19.071 C 6.804 20.946 9.349 22 12 22 C 13.755 22 15.48 21.538 17 20.66 C 18.52 19.783 19.783 18.52 20.66 17 C 21.538 15.48 22 13.755 22 12 C 22 10.245 21.538 8.52 20.66 7 C 19.783 5.48 18.52 4.217 17 3.34 C 15.48 2.462 13.755 2 12 2 M 12 20 C 7.59 20 4 16.41 4 12 C 4 7.59 7.59 4 12 4 C 16.41 4 20 7.59 20 12 C 20 16.41 16.41 20 12 20 M 7 13 L 7 13 L 17 13 L 17 11 L 17 11 L 7 11 L 7 11 L 7 11"
|
||||
android:valueTo="M 12 2 C 9.217 2 6.689 3.152 4.872 5.004 C 3.098 6.811 2 9.283 2 12 C 2 14.856 3.213 17.442 5.149 19.268 C 6.942 20.96 9.356 22 12 22 C 14.061 22 15.982 21.368 17.578 20.288 C 19.114 19.249 20.349 17.796 21.119 16.092 C 21.685 14.841 22 13.456 22 12 C 22 10.122 21.475 8.361 20.566 6.856 C 19.691 5.408 18.46 4.197 16.997 3.347 C 15.524 2.491 13.817 2 12 2 M 12 20 C 7.59 20 4 16.41 4 12 C 4 7.59 7.59 4 12 4 C 16.41 4 20 7.59 20 12 C 20 16.41 16.41 20 12 20 M 6 13 L 10 17 L 18 9 L 16.59 7.58 L 16.59 7.58 L 10 14.17 L 7.41 11.59 L 6 13"
|
@@ -19,7 +19,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 9 14 L 9 21 L 4 21 L 4 9 L 12 3 L 12 3 L 20 9 L 20 21 L 15 21 L 15 14 L 9 14 M 12 13.4 L 12 13.4 L 12 13.4 L 12 13.4 L 12 13.4 L 12 13.4 L 12 13.4"
|
||||
android:valueTo="M 9 13 L 9 19 L 6 19 L 6 10 L 12 5.5 L 15 7.75 L 18 10 L 18 19 L 15 19 L 15 13 L 9 13 M 4 21 L 4 9 L 12 3 L 20 9 L 20 21 L 4 21 L 4 21"
|
@@ -19,7 +19,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 9 13 L 9 19 L 6 19 L 6 10 L 12 5.5 L 15 7.75 L 18 10 L 18 19 L 15 19 L 15 13 L 9 13 M 4 21 L 4 9 L 12 3 L 20 9 L 20 21 L 4 21 L 4 21"
|
||||
android:valueTo="M 9 14 L 9 21 L 4 21 L 4 9 L 12 3 L 12 3 L 20 9 L 20 21 L 15 21 L 15 14 L 9 14 M 12 13.4 L 12 13.4 L 12 13.4 L 12 13.4 L 12 13.4 L 12 13.4 L 12 13.4"
|
@@ -18,7 +18,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 23 13.5 C 23 14.163 22.736 14.799 22.268 15.268 C 21.799 15.736 21.163 16 20.5 16 C 20 16 19.5 16 19 16 L 19 20 C 19 20.53 18.789 21.039 18.414 21.414 C 18.039 21.789 17.53 22 17 22 L 15.1 22 L 13.2 22 C 13.2 21.5 13.2 21 13.2 20.5 C 13.2 19 12 17.8 10.5 17.8 C 9 17.8 7.8 19 7.8 20.5 L 7.8 22 L 4 22 C 3.47 22 2.961 21.789 2.586 21.414 C 2.211 21.039 2 20.53 2 20 L 2 16.2 L 3.5 16.2 C 5 16.2 6.2 15 6.2 13.5 C 6.2 12 5 10.8 3.5 10.8 L 2 10.8 L 2 7 C 2 6.47 2.211 5.961 2.586 5.586 C 2.961 5.211 3.47 5 4 5 L 8 5 C 8 4.5 8 4 8 3.5 C 8 2.837 8.264 2.201 8.732 1.732 C 9.201 1.264 9.837 1 10.5 1 C 11.163 1 11.799 1.264 12.268 1.732 C 12.736 2.201 13 2.837 13 3.5 C 13 4 13 4.5 13 5 L 17 5 C 17.55 5 18.05 5.223 18.413 5.584 C 18.775 5.945 19 6.445 19 7 L 19 11 C 19.5 11 20 11 20.5 11 C 20.5 11 20.5 11 20.5 11 C 21.163 11 21.799 11.264 22.268 11.732 C 22.736 12.201 23 12.837 23 13.5 M 12 12 L 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12"
|
||||
android:valueTo="M 22 13.5 C 22 14.087 21.856 14.64 21.6 15.126 C 21.344 15.612 20.978 16.03 20.533 16.347 C 20.089 16.664 19.567 16.88 19 16.96 L 19 20 C 19 20.53 18.789 21.039 18.414 21.414 C 18.039 21.789 17.53 22 17 22 L 13.2 22 L 13.2 21.7 C 13.2 20.984 12.915 20.297 12.409 19.791 C 11.903 19.285 11.216 19 10.5 19 C 9 19 7.8 20.21 7.8 21.7 L 7.8 22 L 4 22 C 3.47 22 2.961 21.789 2.586 21.414 C 2.211 21.039 2 20.53 2 20 L 2 16.2 L 2.3 16.2 C 3.79 16.2 5 15 5 13.5 C 5 12 3.79 10.8 2.3 10.8 L 2 10.8 L 2 7 C 2 6.47 2.211 5.961 2.586 5.586 C 2.961 5.211 3.47 5 4 5 L 7.04 5 C 7.12 4.433 7.336 3.911 7.653 3.467 C 7.97 3.022 8.388 2.656 8.874 2.4 C 9.36 2.144 9.913 2 10.5 2 C 11.087 2 11.64 2.144 12.126 2.4 C 12.612 2.656 13.03 3.022 13.347 3.467 C 13.664 3.911 13.88 4.433 13.96 5 L 17 5 C 17.53 5 18.039 5.211 18.414 5.586 C 18.789 5.961 19 6.47 19 7 L 19 10.04 C 19.425 10.1 19.825 10.236 20.186 10.434 C 20.547 10.633 20.869 10.893 21.137 11.2 C 21.406 11.508 21.622 11.863 21.77 12.251 C 21.919 12.639 22 13.06 22 13.5 M 17 12 L 18.5 12 C 18.898 12 19.279 12.158 19.561 12.439 C 19.842 12.721 20 13.102 20 13.5 C 20 13.898 19.842 14.279 19.561 14.561 C 19.279 14.842 18.898 15 18.5 15 L 17 15 L 17 15 L 17 20 L 14.88 20 C 14.2 18.25 12.5 17 10.5 17 C 8.5 17 6.8 18.25 6.12 20 L 4 20 L 4 17.88 C 5.75 17.2 7 15.5 7 13.5 C 7 11.5 5.76 9.8 4 9.12 L 4 7 L 9 7 L 9 5.5 C 9 5.102 9.158 4.721 9.439 4.439 C 9.721 4.158 10.102 4 10.5 4 C 10.898 4 11.279 4.158 11.561 4.439 C 11.842 4.721 12 5.102 12 5.5 L 12 7 L 17 7 L 17 12"
|
@@ -18,7 +18,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 22 13.5 C 22 14.087 21.856 14.64 21.6 15.126 C 21.344 15.612 20.978 16.03 20.533 16.347 C 20.089 16.664 19.567 16.88 19 16.96 L 19 20 C 19 20.53 18.789 21.039 18.414 21.414 C 18.039 21.789 17.53 22 17 22 L 13.2 22 L 13.2 21.7 C 13.2 20.984 12.915 20.297 12.409 19.791 C 11.903 19.285 11.216 19 10.5 19 C 9 19 7.8 20.21 7.8 21.7 L 7.8 22 L 4 22 C 3.47 22 2.961 21.789 2.586 21.414 C 2.211 21.039 2 20.53 2 20 L 2 16.2 L 2.3 16.2 C 3.79 16.2 5 15 5 13.5 C 5 12 3.79 10.8 2.3 10.8 L 2 10.8 L 2 7 C 2 6.47 2.211 5.961 2.586 5.586 C 2.961 5.211 3.47 5 4 5 L 7.04 5 C 7.12 4.433 7.336 3.911 7.653 3.467 C 7.97 3.022 8.388 2.656 8.874 2.4 C 9.36 2.144 9.913 2 10.5 2 C 11.087 2 11.64 2.144 12.126 2.4 C 12.612 2.656 13.03 3.022 13.347 3.467 C 13.664 3.911 13.88 4.433 13.96 5 L 17 5 C 17.53 5 18.039 5.211 18.414 5.586 C 18.789 5.961 19 6.47 19 7 L 19 10.04 C 19.425 10.1 19.825 10.236 20.186 10.434 C 20.547 10.633 20.869 10.893 21.137 11.2 C 21.406 11.508 21.622 11.863 21.77 12.251 C 21.919 12.639 22 13.06 22 13.5 M 17 12 L 18.5 12 C 18.898 12 19.279 12.158 19.561 12.439 C 19.842 12.721 20 13.102 20 13.5 C 20 13.898 19.842 14.279 19.561 14.561 C 19.279 14.842 18.898 15 18.5 15 L 17 15 L 17 15 L 17 20 L 14.88 20 C 14.2 18.25 12.5 17 10.5 17 C 8.5 17 6.8 18.25 6.12 20 L 4 20 L 4 17.88 C 5.75 17.2 7 15.5 7 13.5 C 7 11.5 5.76 9.8 4 9.12 L 4 7 L 9 7 L 9 5.5 C 9 5.102 9.158 4.721 9.439 4.439 C 9.721 4.158 10.102 4 10.5 4 C 10.898 4 11.279 4.158 11.561 4.439 C 11.842 4.721 12 5.102 12 5.5 L 12 7 L 17 7 L 17 12"
|
||||
android:valueTo="M 23 13.5 C 23 14.163 22.736 14.799 22.268 15.268 C 21.799 15.736 21.163 16 20.5 16 C 20 16 19.5 16 19 16 L 19 20 C 19 20.53 18.789 21.039 18.414 21.414 C 18.039 21.789 17.53 22 17 22 L 15.1 22 L 13.2 22 C 13.2 21.5 13.2 21 13.2 20.5 C 13.2 19 12 17.8 10.5 17.8 C 9 17.8 7.8 19 7.8 20.5 L 7.8 22 L 4 22 C 3.47 22 2.961 21.789 2.586 21.414 C 2.211 21.039 2 20.53 2 20 L 2 16.2 L 3.5 16.2 C 5 16.2 6.2 15 6.2 13.5 C 6.2 12 5 10.8 3.5 10.8 L 2 10.8 L 2 7 C 2 6.47 2.211 5.961 2.586 5.586 C 2.961 5.211 3.47 5 4 5 L 8 5 C 8 4.5 8 4 8 3.5 C 8 2.837 8.264 2.201 8.732 1.732 C 9.201 1.264 9.837 1 10.5 1 C 11.163 1 11.799 1.264 12.268 1.732 C 12.736 2.201 13 2.837 13 3.5 C 13 4 13 4.5 13 5 L 17 5 C 17.55 5 18.05 5.223 18.413 5.584 C 18.775 5.945 19 6.445 19 7 L 19 11 C 19.5 11 20 11 20.5 11 C 20.5 11 20.5 11 20.5 11 C 21.163 11 21.799 11.264 22.268 11.732 C 22.736 12.201 23 12.837 23 13.5 M 12 12 L 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12"
|
@@ -18,7 +18,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 14.87 5.07 L 14.5 2.42 C 14.46 2.18 14.25 2 14 2 L 10 2 C 9.75 2 9.54 2.18 9.5 2.42 L 9.13 5.07 C 8.5 5.32 7.96 5.66 7.44 6.05 L 4.95 5.05 C 4.73 4.96 4.46 5.05 4.34 5.27 L 2.34 8.73 C 2.21 8.95 2.27 9.22 2.46 9.37 L 4.57 11 C 4.53 11.34 4.5 11.67 4.5 12 C 4.5 12.33 4.53 12.65 4.57 12.97 L 2.46 14.63 C 2.27 14.78 2.21 15.05 2.34 15.27 L 4.34 18.73 C 4.46 18.95 4.73 19.03 4.95 18.95 L 7.44 17.94 C 7.96 18.34 8.5 18.68 9.13 18.93 L 9.5 21.58 C 9.54 21.82 9.75 22 10 22 L 14 22 C 14.25 22 14.46 21.82 14.5 21.58 L 14.87 18.93 C 15.5 18.67 16.04 18.34 16.56 17.94 L 19.05 18.95 C 19.27 19.03 19.54 18.95 19.66 18.73 L 21.66 15.27 C 21.78 15.05 21.73 14.78 21.54 14.63 L 19.43 12.97 L 19.43 12.97 C 19.47 12.65 19.5 12.33 19.5 12 C 19.5 11.67 19.47 11.34 19.43 11 L 21.54 9.37 C 21.73 9.22 21.78 8.95 21.66 8.73 L 19.66 5.27 C 19.54 5.05 19.27 4.96 19.05 5.05 L 16.56 6.05 C 16.04 5.66 15.5 5.32 14.87 5.07 M 12 8.5 C 12.614 8.5 13.218 8.662 13.75 8.969 C 14.282 9.276 14.724 9.718 15.031 10.25 C 15.338 10.782 15.5 11.386 15.5 12 C 15.5 12.614 15.338 13.218 15.031 13.75 C 14.724 14.282 14.282 14.724 13.75 15.031 C 13.218 15.338 12.614 15.5 12 15.5 C 11.072 15.5 10.181 15.131 9.525 14.475 C 8.869 13.819 8.5 12.928 8.5 12 C 8.5 11.072 8.869 10.181 9.525 9.525 C 10.181 8.869 11.072 8.5 12 8.5 M 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 M 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12"
|
||||
android:valueTo="M 14.87 5.07 L 14.5 2.42 C 14.46 2.18 14.25 2 14 2 L 10 2 C 9.75 2 9.54 2.18 9.5 2.42 L 9.13 5.07 C 8.5 5.32 7.96 5.66 7.44 6.05 L 4.95 5.05 C 4.73 4.96 4.46 5.05 4.34 5.27 L 2.34 8.73 C 2.21 8.95 2.27 9.22 2.46 9.37 L 4.57 11 C 4.547 11.333 4.523 11.667 4.5 12 C 4.523 12.323 4.547 12.647 4.57 12.97 L 2.46 14.63 C 2.27 14.78 2.21 15.05 2.34 15.27 L 4.34 18.73 C 4.46 18.95 4.73 19.03 4.95 18.95 L 7.44 17.94 C 7.96 18.34 8.5 18.68 9.13 18.93 L 9.5 21.58 C 9.54 21.82 9.75 22 10 22 L 14 22 C 14.25 22 14.46 21.82 14.5 21.58 L 14.87 18.93 C 15.5 18.68 16.04 18.34 16.56 17.95 L 19.05 18.95 C 19.27 19.04 19.54 18.95 19.66 18.73 L 21.66 15.27 C 21.79 15.05 21.73 14.78 21.54 14.63 L 19.43 13 L 19.465 12.499 C 19.477 12.333 19.488 12.166 19.5 12 C 19.477 11.667 19.453 11.333 19.43 11 L 21.54 9.37 C 21.73 9.22 21.79 8.95 21.66 8.73 L 19.66 5.27 C 19.54 5.05 19.27 4.96 19.05 5.05 L 16.56 6.05 C 16.04 5.66 15.5 5.32 14.87 5.07 M 12 8 C 12.53 8 13.05 8.105 13.531 8.305 C 14.011 8.504 14.454 8.797 14.828 9.172 C 15.578 9.921 16 10.94 16 12 C 16 12.53 15.895 13.05 15.695 13.531 C 15.496 14.011 15.203 14.454 14.828 14.828 C 14.079 15.578 13.06 16 12 16 C 10.94 16 9.921 15.578 9.172 14.828 C 8.422 14.079 8 13.06 8 12 C 8 10.94 8.422 9.921 9.172 9.172 C 9.921 8.422 10.94 8 12 8 M 12 10 C 11.912 10 11.824 10.006 11.737 10.017 C 11.651 10.029 11.565 10.046 11.481 10.069 C 11.397 10.091 11.315 10.119 11.235 10.152 C 11.155 10.186 11.077 10.224 11.001 10.267 C 10.926 10.311 10.854 10.359 10.784 10.412 C 10.715 10.466 10.649 10.524 10.586 10.586 C 10.524 10.649 10.466 10.715 10.412 10.784 C 10.359 10.854 10.311 10.926 10.267 11.001 C 10.224 11.077 10.186 11.155 10.152 11.235 C 10.119 11.315 10.091 11.397 10.069 11.481 C 10.046 11.565 10.029 11.651 10.017 11.737 C 10.006 11.824 10 11.912 10 12 C 10 12.088 10.006 12.176 10.017 12.263 C 10.029 12.349 10.046 12.435 10.069 12.519 C 10.091 12.603 10.119 12.685 10.152 12.765 C 10.186 12.845 10.224 12.923 10.267 12.999 C 10.311 13.074 10.359 13.146 10.412 13.216 C 10.466 13.285 10.524 13.351 10.586 13.414 C 10.649 13.476 10.715 13.534 10.784 13.588 C 10.854 13.641 10.926 13.689 11.001 13.733 C 11.077 13.776 11.155 13.814 11.235 13.848 C 11.315 13.881 11.397 13.909 11.481 13.931 C 11.565 13.954 11.651 13.971 11.737 13.983 C 11.824 13.994 11.912 14 12 14 C 12.53 14 13.039 13.789 13.414 13.414 C 13.468 13.36 13.518 13.304 13.565 13.245 C 13.611 13.187 13.655 13.126 13.694 13.062 C 13.734 12.999 13.77 12.934 13.802 12.867 C 13.834 12.8 13.863 12.731 13.887 12.661 C 13.912 12.591 13.933 12.519 13.949 12.447 C 13.966 12.374 13.979 12.3 13.987 12.226 C 13.996 12.151 14 12.076 14 12 C 14 11.912 13.994 11.824 13.983 11.737 C 13.971 11.651 13.954 11.565 13.931 11.481 C 13.909 11.397 13.881 11.315 13.848 11.235 C 13.814 11.155 13.776 11.077 13.733 11.001 C 13.689 10.926 13.641 10.854 13.588 10.784 C 13.534 10.715 13.476 10.649 13.414 10.586 C 13.039 10.211 12.53 10 12 10 M 11.25 4 L 11.25 4 L 12.75 4 L 13.12 6.62 C 14.32 6.86 15.38 7.5 16.15 8.39 L 18.56 7.35 L 19.31 8.65 L 17.2 10.2 C 17.6 11.37 17.6 12.64 17.2 13.81 L 19.32 15.36 L 18.57 16.66 L 16.14 15.62 C 15.37 16.5 14.32 17.14 13.13 17.39 L 12.76 20 L 11.24 20 L 10.87 17.38 C 9.68 17.14 8.63 16.5 7.86 15.62 L 5.43 16.66 L 4.68 15.36 L 6.8 13.8 C 6.4 12.64 6.4 11.37 6.8 10.2 L 4.69 8.65 L 5.44 7.35 L 7.85 8.39 C 8.62 7.5 9.68 6.86 10.88 6.61 L 11.25 4"
|
@@ -18,7 +18,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 14.87 5.07 L 14.5 2.42 C 14.46 2.18 14.25 2 14 2 L 10 2 C 9.75 2 9.54 2.18 9.5 2.42 L 9.13 5.07 C 8.5 5.32 7.96 5.66 7.44 6.05 L 4.95 5.05 C 4.73 4.96 4.46 5.05 4.34 5.27 L 2.34 8.73 C 2.21 8.95 2.27 9.22 2.46 9.37 L 4.57 11 C 4.547 11.333 4.523 11.667 4.5 12 C 4.523 12.323 4.547 12.647 4.57 12.97 L 2.46 14.63 C 2.27 14.78 2.21 15.05 2.34 15.27 L 4.34 18.73 C 4.46 18.95 4.73 19.03 4.95 18.95 L 7.44 17.94 C 7.96 18.34 8.5 18.68 9.13 18.93 L 9.5 21.58 C 9.54 21.82 9.75 22 10 22 L 14 22 C 14.25 22 14.46 21.82 14.5 21.58 L 14.87 18.93 C 15.5 18.68 16.04 18.34 16.56 17.95 L 19.05 18.95 C 19.27 19.04 19.54 18.95 19.66 18.73 L 21.66 15.27 C 21.79 15.05 21.73 14.78 21.54 14.63 L 19.43 13 L 19.465 12.499 C 19.477 12.333 19.488 12.166 19.5 12 C 19.477 11.667 19.453 11.333 19.43 11 L 21.54 9.37 C 21.73 9.22 21.79 8.95 21.66 8.73 L 19.66 5.27 C 19.54 5.05 19.27 4.96 19.05 5.05 L 16.56 6.05 C 16.04 5.66 15.5 5.32 14.87 5.07 M 12 8 C 12.53 8 13.05 8.105 13.531 8.305 C 14.011 8.504 14.454 8.797 14.828 9.172 C 15.578 9.921 16 10.94 16 12 C 16 12.53 15.895 13.05 15.695 13.531 C 15.496 14.011 15.203 14.454 14.828 14.828 C 14.079 15.578 13.06 16 12 16 C 10.94 16 9.921 15.578 9.172 14.828 C 8.422 14.079 8 13.06 8 12 C 8 10.94 8.422 9.921 9.172 9.172 C 9.921 8.422 10.94 8 12 8 M 12 10 C 11.912 10 11.824 10.006 11.737 10.017 C 11.651 10.029 11.565 10.046 11.481 10.069 C 11.397 10.091 11.315 10.119 11.235 10.152 C 11.155 10.186 11.077 10.224 11.001 10.267 C 10.926 10.311 10.854 10.359 10.784 10.412 C 10.715 10.466 10.649 10.524 10.586 10.586 C 10.524 10.649 10.466 10.715 10.412 10.784 C 10.359 10.854 10.311 10.926 10.267 11.001 C 10.224 11.077 10.186 11.155 10.152 11.235 C 10.119 11.315 10.091 11.397 10.069 11.481 C 10.046 11.565 10.029 11.651 10.017 11.737 C 10.006 11.824 10 11.912 10 12 C 10 12.088 10.006 12.176 10.017 12.263 C 10.029 12.349 10.046 12.435 10.069 12.519 C 10.091 12.603 10.119 12.685 10.152 12.765 C 10.186 12.845 10.224 12.923 10.267 12.999 C 10.311 13.074 10.359 13.146 10.412 13.216 C 10.466 13.285 10.524 13.351 10.586 13.414 C 10.649 13.476 10.715 13.534 10.784 13.588 C 10.854 13.641 10.926 13.689 11.001 13.733 C 11.077 13.776 11.155 13.814 11.235 13.848 C 11.315 13.881 11.397 13.909 11.481 13.931 C 11.565 13.954 11.651 13.971 11.737 13.983 C 11.824 13.994 11.912 14 12 14 C 12.53 14 13.039 13.789 13.414 13.414 C 13.468 13.36 13.518 13.304 13.565 13.245 C 13.611 13.187 13.655 13.126 13.694 13.062 C 13.734 12.999 13.77 12.934 13.802 12.867 C 13.834 12.8 13.863 12.731 13.887 12.661 C 13.912 12.591 13.933 12.519 13.949 12.447 C 13.966 12.374 13.979 12.3 13.987 12.226 C 13.996 12.151 14 12.076 14 12 C 14 11.912 13.994 11.824 13.983 11.737 C 13.971 11.651 13.954 11.565 13.931 11.481 C 13.909 11.397 13.881 11.315 13.848 11.235 C 13.814 11.155 13.776 11.077 13.733 11.001 C 13.689 10.926 13.641 10.854 13.588 10.784 C 13.534 10.715 13.476 10.649 13.414 10.586 C 13.039 10.211 12.53 10 12 10 M 11.25 4 L 11.25 4 L 12.75 4 L 13.12 6.62 C 14.32 6.86 15.38 7.5 16.15 8.39 L 18.56 7.35 L 19.31 8.65 L 17.2 10.2 C 17.6 11.37 17.6 12.64 17.2 13.81 L 19.32 15.36 L 18.57 16.66 L 16.14 15.62 C 15.37 16.5 14.32 17.14 13.13 17.39 L 12.76 20 L 11.24 20 L 10.87 17.38 C 9.68 17.14 8.63 16.5 7.86 15.62 L 5.43 16.66 L 4.68 15.36 L 6.8 13.8 C 6.4 12.64 6.4 11.37 6.8 10.2 L 4.69 8.65 L 5.44 7.35 L 7.85 8.39 C 8.62 7.5 9.68 6.86 10.88 6.61 L 11.25 4"
|
||||
android:valueTo="M 14.87 5.07 L 14.5 2.42 C 14.46 2.18 14.25 2 14 2 L 10 2 C 9.75 2 9.54 2.18 9.5 2.42 L 9.13 5.07 C 8.5 5.32 7.96 5.66 7.44 6.05 L 4.95 5.05 C 4.73 4.96 4.46 5.05 4.34 5.27 L 2.34 8.73 C 2.21 8.95 2.27 9.22 2.46 9.37 L 4.57 11 C 4.53 11.34 4.5 11.67 4.5 12 C 4.5 12.33 4.53 12.65 4.57 12.97 L 2.46 14.63 C 2.27 14.78 2.21 15.05 2.34 15.27 L 4.34 18.73 C 4.46 18.95 4.73 19.03 4.95 18.95 L 7.44 17.94 C 7.96 18.34 8.5 18.68 9.13 18.93 L 9.5 21.58 C 9.54 21.82 9.75 22 10 22 L 14 22 C 14.25 22 14.46 21.82 14.5 21.58 L 14.87 18.93 C 15.5 18.67 16.04 18.34 16.56 17.94 L 19.05 18.95 C 19.27 19.03 19.54 18.95 19.66 18.73 L 21.66 15.27 C 21.78 15.05 21.73 14.78 21.54 14.63 L 19.43 12.97 L 19.43 12.97 C 19.47 12.65 19.5 12.33 19.5 12 C 19.5 11.67 19.47 11.34 19.43 11 L 21.54 9.37 C 21.73 9.22 21.78 8.95 21.66 8.73 L 19.66 5.27 C 19.54 5.05 19.27 4.96 19.05 5.05 L 16.56 6.05 C 16.04 5.66 15.5 5.32 14.87 5.07 M 12 8.5 C 12.614 8.5 13.218 8.662 13.75 8.969 C 14.282 9.276 14.724 9.718 15.031 10.25 C 15.338 10.782 15.5 11.386 15.5 12 C 15.5 12.614 15.338 13.218 15.031 13.75 C 14.724 14.282 14.282 14.724 13.75 15.031 C 13.218 15.338 12.614 15.5 12 15.5 C 11.072 15.5 10.181 15.131 9.525 14.475 C 8.869 13.819 8.5 12.928 8.5 12 C 8.5 11.072 8.869 10.181 9.525 9.525 C 10.181 8.869 11.072 8.5 12 8.5 M 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 C 11.982 12 11.982 12 11.982 12 M 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12 L 12 12 L 12 12 C 12 12 12 12 12 12 L 12 12"
|
@@ -18,7 +18,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 21 11 C 21 16.55 17.16 21.74 12 23 C 6.84 21.74 3 16.55 3 11 L 3 5 L 12 1 L 12 1 L 21 5 L 21 11 M 12 10.18 L 12 10.18 C 12 10.18 12 10.18 12 10.18 L 12 10.18 L 12 10.18 L 12 10.18 L 12 10.18 C 12 10.18 12 10.18 12 10.18"
|
||||
android:valueTo="M 21 11 C 21 16.55 17.16 21.74 12 23 C 6.84 21.74 3 16.55 3 11 L 3 5 L 7.5 3 L 12 1 L 21 5 L 21 11 M 12 21 L 12 21 C 8.25 20 5 15.54 5 11.22 L 5 6.3 L 12 3.18 L 19 6.3 L 19 11.22 C 19 15.54 15.75 20 12 21"
|
@@ -18,7 +18,7 @@
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:interpolator="@interpolator/fast_out_slow_in"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||
android:propertyName="pathData"
|
||||
android:valueFrom="M 21 11 C 21 16.55 17.16 21.74 12 23 C 6.84 21.74 3 16.55 3 11 L 3 5 L 7.5 3 L 12 1 L 21 5 L 21 11 M 12 21 L 12 21 C 8.25 20 5 15.54 5 11.22 L 5 6.3 L 12 3.18 L 19 6.3 L 19 11.22 C 19 15.54 15.75 20 12 21"
|
||||
android:valueTo="M 21 11 C 21 16.55 17.16 21.74 12 23 C 6.84 21.74 3 16.55 3 11 L 3 5 L 12 1 L 12 1 L 21 5 L 21 11 M 12 10.18 L 12 10.18 C 12 10.18 12 10.18 12 10.18 L 12 10.18 L 12 10.18 L 12 10.18 L 12 10.18 C 12 10.18 12 10.18 12 10.18"
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user