mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-14 17:45:23 +00:00
Compare commits
907 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9476e7282d | ||
![]() |
251c3c3e0e | ||
![]() |
cd0eca20b0 | ||
![]() |
6839cb9ab2 | ||
![]() |
d11a3397d8 | ||
![]() |
975120d6a6 | ||
![]() |
e489b3b6dd | ||
![]() |
589a270b8d | ||
![]() |
7961be5cfa | ||
![]() |
959430e030 | ||
![]() |
2923c8ccd1 | ||
![]() |
7df4a9d74f | ||
![]() |
bf4ed295da | ||
![]() |
a5fca960dc | ||
![]() |
f99912b9db | ||
![]() |
a54bdb54e4 | ||
![]() |
cd9851a1fe | ||
![]() |
9ca469898c | ||
![]() |
0665549473 | ||
![]() |
9d7a14b335 | ||
![]() |
62e29fee74 | ||
![]() |
e472db552b | ||
![]() |
466e4bd4e1 | ||
![]() |
4cf525c588 | ||
![]() |
c8aec2510d | ||
![]() |
ccbfe0e66e | ||
![]() |
23ea28de6f | ||
![]() |
55c3ee3a6f | ||
![]() |
2a42ca2b8f | ||
![]() |
a897e82fa4 | ||
![]() |
ffa15831d3 | ||
![]() |
a344ebf28c | ||
![]() |
78f7fa348e | ||
![]() |
d8c448b99d | ||
![]() |
d4b83b6a44 | ||
![]() |
e5d36d1d24 | ||
![]() |
ff18cb8e70 | ||
![]() |
37a9724a54 | ||
![]() |
d660401063 | ||
![]() |
88541d6f49 | ||
![]() |
ecd6129fe5 | ||
![]() |
6dfe9df9e2 | ||
![]() |
e81de7ec36 | ||
![]() |
c78da1ce24 | ||
![]() |
7b2d40987c | ||
![]() |
3a37e8c9c5 | ||
![]() |
58b405bce1 | ||
![]() |
810174ef73 | ||
![]() |
690a5ac033 | ||
![]() |
89aad31f7e | ||
![]() |
7124db98e3 | ||
![]() |
0860e859f7 | ||
![]() |
04008949b8 | ||
![]() |
39f2940bd1 | ||
![]() |
1460317ebd | ||
![]() |
12340c9bd5 | ||
![]() |
c4590fe2ba | ||
![]() |
b36066bbcd | ||
![]() |
65d1c5827c | ||
![]() |
1d675c8b2e | ||
![]() |
0b494ed7df | ||
![]() |
48d9fc24eb | ||
![]() |
83426f7f36 | ||
![]() |
0e86d4dbcb | ||
![]() |
5e050d7456 | ||
![]() |
898580bf90 | ||
![]() |
86621a4c46 | ||
![]() |
a834e72b71 | ||
![]() |
d8cf42af16 | ||
![]() |
8c79d66b7b | ||
![]() |
fada8b148a | ||
![]() |
dc0acea47c | ||
![]() |
78d1200608 | ||
![]() |
527bbc0368 | ||
![]() |
4c89c7e2b3 | ||
![]() |
adbea7e313 | ||
![]() |
76962f965e | ||
![]() |
a4b8c5e46b | ||
![]() |
83c707439c | ||
![]() |
25dd6121f4 | ||
![]() |
67f35ad027 | ||
![]() |
0c4b8afbc5 | ||
![]() |
34b30d7ce1 | ||
![]() |
2215088973 | ||
![]() |
8b7fb6cdde | ||
![]() |
94c7dbedf2 | ||
![]() |
b1dc47a047 | ||
![]() |
62b1310d97 | ||
![]() |
0a86916d3a | ||
![]() |
9907ce57aa | ||
![]() |
b92626cacc | ||
![]() |
5a762f0a8e | ||
![]() |
5dd7a7d804 | ||
![]() |
7831f40691 | ||
![]() |
4f4b1ff885 | ||
![]() |
97901979dd | ||
![]() |
287316842c | ||
![]() |
608786e8f3 | ||
![]() |
9684a35cab | ||
![]() |
e3e4202954 | ||
![]() |
23c2054d46 | ||
![]() |
a20a2a8fa0 | ||
![]() |
a2896be4a6 | ||
![]() |
e9220a28d9 | ||
![]() |
cf12087e21 | ||
![]() |
00c1b36837 | ||
![]() |
03e034795d | ||
![]() |
79c0fafe43 | ||
![]() |
d499819ba0 | ||
![]() |
86da917174 | ||
![]() |
30bd7d6555 | ||
![]() |
e5a12f0f5f | ||
![]() |
c85a8434c6 | ||
![]() |
427a1ca4e5 | ||
![]() |
22884e173a | ||
![]() |
d1829308e9 | ||
![]() |
73840f8721 | ||
![]() |
c7d1af9805 | ||
![]() |
4ad26d3dfb | ||
![]() |
0c70b7670c | ||
![]() |
f44d044095 | ||
![]() |
5c1cb13472 | ||
![]() |
3327fc668e | ||
![]() |
610945ac54 | ||
![]() |
ddf5474917 | ||
![]() |
6ba1685ade | ||
![]() |
e02b5f7868 | ||
![]() |
ab2e5d1e7e | ||
![]() |
f3fef7bfe4 | ||
![]() |
c34c7838bb | ||
![]() |
c8a16b0e0c | ||
![]() |
14f9ed91a1 | ||
![]() |
7a207d4ccf | ||
![]() |
92a42d901f | ||
![]() |
084d89fcce | ||
![]() |
55b036c071 | ||
![]() |
30e79310ab | ||
![]() |
f063fa5054 | ||
![]() |
7bd901273c | ||
![]() |
c1e061603b | ||
![]() |
cb08504fe5 | ||
![]() |
c0a1fb77be | ||
![]() |
4864c1112a | ||
![]() |
9ddeab034b | ||
![]() |
c4847ed288 | ||
![]() |
b8f1523fb2 | ||
![]() |
fb7fa8a6b3 | ||
![]() |
9c7d359093 | ||
![]() |
eb54bc1fd7 | ||
![]() |
d4a0286e13 | ||
![]() |
83e66767ff | ||
![]() |
7dc010749b | ||
![]() |
8e8d013b1b | ||
![]() |
bba0373808 | ||
![]() |
1fa318dc8c | ||
![]() |
6edc5e2037 | ||
![]() |
1523ed9f78 | ||
![]() |
8e604d2ab8 | ||
![]() |
2aba7247a9 | ||
![]() |
e66fe8533e | ||
![]() |
b03fbb3917 | ||
![]() |
c2ece62e4c | ||
![]() |
8c972dcf34 | ||
![]() |
50af14f2a3 | ||
![]() |
e0a356b319 | ||
![]() |
c09a792958 | ||
![]() |
0bbfe7f44d | ||
![]() |
a396abf565 | ||
![]() |
1e3edb8883 | ||
![]() |
3b8b61bf35 | ||
![]() |
6f90456036 | ||
![]() |
f56fd4e215 | ||
![]() |
aa35aac5d5 | ||
![]() |
1f162b819d | ||
![]() |
52ef1d1cb2 | ||
![]() |
f14e3a89cc | ||
![]() |
95d3eac2e0 | ||
![]() |
8e73536e02 | ||
![]() |
12a0870bc9 | ||
![]() |
6ff82c4e86 | ||
![]() |
c64de35375 | ||
![]() |
ee5283f4e8 | ||
![]() |
bd0e954fea | ||
![]() |
675471a49e | ||
![]() |
c90e73ccec | ||
![]() |
a43c1267d8 | ||
![]() |
e8958c6b5c | ||
![]() |
e8a3bf82c6 | ||
![]() |
27fd79176a | ||
![]() |
28d86a3454 | ||
![]() |
c6c1a17ae6 | ||
![]() |
2b47d47215 | ||
![]() |
0e82df9e10 | ||
![]() |
893821ad88 | ||
![]() |
6b80fbfa99 | ||
![]() |
8c3c7d0194 | ||
![]() |
b94a3d9f2f | ||
![]() |
442d0b5ddc | ||
![]() |
494615d9a0 | ||
![]() |
afbfb81837 | ||
![]() |
3ed4e258a3 | ||
![]() |
dddd41c95b | ||
![]() |
5f2ca81e86 | ||
![]() |
c9eac0c438 | ||
![]() |
b6b34f7612 | ||
![]() |
e55c413261 | ||
![]() |
0399cde50a | ||
![]() |
019eb03823 | ||
![]() |
363410e1c0 | ||
![]() |
fc2ef21660 | ||
![]() |
18cb659ff3 | ||
![]() |
63231d97ce | ||
![]() |
9ac81a8a25 | ||
![]() |
79af2787ae | ||
![]() |
f5f9b285c0 | ||
![]() |
6c05f2ae85 | ||
![]() |
29043e1684 | ||
![]() |
b73d4a7022 | ||
![]() |
ad95e8951b | ||
![]() |
bf591fca12 | ||
![]() |
dcf027884d | ||
![]() |
584f3820fe | ||
![]() |
3c7c46307a | ||
![]() |
4d80361805 | ||
![]() |
9a74e19117 | ||
![]() |
b1e17706a4 | ||
![]() |
caad129d69 | ||
![]() |
da58571ce5 | ||
![]() |
2aa7f1c094 | ||
![]() |
823e31a91b | ||
![]() |
fb926ae302 | ||
![]() |
e0489eeffd | ||
![]() |
dc9d5a4cac | ||
![]() |
143743d0b0 | ||
![]() |
563f0d5ad5 | ||
![]() |
c99f4a591b | ||
![]() |
449204e380 | ||
![]() |
a85c4c6528 | ||
![]() |
d203a6fff6 | ||
![]() |
6c612d66d7 | ||
![]() |
540253a55b | ||
![]() |
15b7c4ccd1 | ||
![]() |
442d5335ea | ||
![]() |
8a80eea597 | ||
![]() |
5e35703091 | ||
![]() |
b7ca73f431 | ||
![]() |
a14fc90f07 | ||
![]() |
c913f7ec74 | ||
![]() |
7f6c9e8411 | ||
![]() |
bb02ea3a20 | ||
![]() |
3981c9665e | ||
![]() |
88628fdf3c | ||
![]() |
0469817781 | ||
![]() |
a786801141 | ||
![]() |
ab86732c89 | ||
![]() |
59622d1688 | ||
![]() |
58a25a3e2b | ||
![]() |
15dca29a87 | ||
![]() |
46980819c0 | ||
![]() |
4fb6a7268c | ||
![]() |
c05e963f37 | ||
![]() |
7f7f625864 | ||
![]() |
b25aa8295a | ||
![]() |
15a605765c | ||
![]() |
b575c95710 | ||
![]() |
a48a9c858a | ||
![]() |
0d8d6290a3 | ||
![]() |
4dcd733ddd | ||
![]() |
b62835cbeb | ||
![]() |
6ea740b5ab | ||
![]() |
7ab98dd5ac | ||
![]() |
fc8b3400fc | ||
![]() |
54428ba415 | ||
![]() |
95d1e69d8e | ||
![]() |
a0f13ab49f | ||
![]() |
c3e8405020 | ||
![]() |
a93593ea66 | ||
![]() |
23eff70883 | ||
![]() |
110dd4a8b9 | ||
![]() |
d9c2bffc9f | ||
![]() |
049db49dc8 | ||
![]() |
7c1d2ec61e | ||
![]() |
a1b2830c06 | ||
![]() |
82d1d19267 | ||
![]() |
4d4195c02d | ||
![]() |
5637a258fc | ||
![]() |
ee6810f417 | ||
![]() |
7098248c64 | ||
![]() |
0d31d356ef | ||
![]() |
b782e7dcb7 | ||
![]() |
a4671b4698 | ||
![]() |
7edd8be169 | ||
![]() |
24650eefe4 | ||
![]() |
8e1a44e7eb | ||
![]() |
2722875190 | ||
![]() |
3ca6d06f69 | ||
![]() |
10e47248de | ||
![]() |
e73ff679ac | ||
![]() |
53e401fa2d | ||
![]() |
d2768357da | ||
![]() |
a6c2ba7c1e | ||
![]() |
aae5b466fb | ||
![]() |
2b7be8b949 | ||
![]() |
b6511a510d | ||
![]() |
704541aef2 | ||
![]() |
005560a4c5 | ||
![]() |
231a5d1853 | ||
![]() |
9e2b59060d | ||
![]() |
08ea937f7c | ||
![]() |
2baedf74d1 | ||
![]() |
32faa4ced6 | ||
![]() |
ccdb0b5d13 | ||
![]() |
8506b672ad | ||
![]() |
ce2e33bb20 | ||
![]() |
6707b72260 | ||
![]() |
5885b8c20d | ||
![]() |
820710c086 | ||
![]() |
51cf196bf7 | ||
![]() |
dadba44cf9 | ||
![]() |
2ce4a5543b | ||
![]() |
9112a3a4f5 | ||
![]() |
24615afda1 | ||
![]() |
c5778f398b | ||
![]() |
4eb4097b9b | ||
![]() |
c512496847 | ||
![]() |
506961a10d | ||
![]() |
3414415907 | ||
![]() |
dc2ae7cfd1 | ||
![]() |
2e86d21c29 | ||
![]() |
2654382c43 | ||
![]() |
9e26b73813 | ||
![]() |
10cd13bf80 | ||
![]() |
f10ee5f887 | ||
![]() |
47cc532d96 | ||
![]() |
218327f92b | ||
![]() |
4eae66a1a7 | ||
![]() |
b09ceeb43c | ||
![]() |
4fb539c110 | ||
![]() |
849b284da5 | ||
![]() |
895b5f6cbf | ||
![]() |
cb3d4ea514 | ||
![]() |
0d89a2a97d | ||
![]() |
3ca5913055 | ||
![]() |
df6b808f49 | ||
![]() |
09c7ac754b | ||
![]() |
805da67c23 | ||
![]() |
3c6889505b | ||
![]() |
c8e9ce7627 | ||
![]() |
837c679a31 | ||
![]() |
06616659b8 | ||
![]() |
a34c04f999 | ||
![]() |
da43ac89a0 | ||
![]() |
830fc758b9 | ||
![]() |
0f3cfef278 | ||
![]() |
b32d7bfafd | ||
![]() |
c0899f2939 | ||
![]() |
082330808f | ||
![]() |
024da05888 | ||
![]() |
377b6d0cc2 | ||
![]() |
c661009b31 | ||
![]() |
613f2d31c5 | ||
![]() |
7dbb973db5 | ||
![]() |
f4502f8be8 | ||
![]() |
455b13b83c | ||
![]() |
8b98709743 | ||
![]() |
1b12f45f39 | ||
![]() |
a5cad532ff | ||
![]() |
070719db50 | ||
![]() |
28cccdf7aa | ||
![]() |
b7e0986a5c | ||
![]() |
da709745dd | ||
![]() |
8b6771d487 | ||
![]() |
e1b847fbc5 | ||
![]() |
7188de1205 | ||
![]() |
44fb7dbcbe | ||
![]() |
8086b5933c | ||
![]() |
7f675f4bf7 | ||
![]() |
5e6b53e0da | ||
![]() |
5b29fefc65 | ||
![]() |
16a168535d | ||
![]() |
33f70f8f6d | ||
![]() |
4f18a66d73 | ||
![]() |
250dc16007 | ||
![]() |
7af273e047 | ||
![]() |
e381aebaa0 | ||
![]() |
45d91c9658 | ||
![]() |
4a9158f667 | ||
![]() |
0d9ee89e7f | ||
![]() |
abaff72304 | ||
![]() |
b828e2d0b2 | ||
![]() |
53d7cbc11b | ||
![]() |
310be7ab47 | ||
![]() |
60894e458f | ||
![]() |
fbebb6ac10 | ||
![]() |
a9f8c20703 | ||
![]() |
ae0b15d197 | ||
![]() |
869aa62328 | ||
![]() |
dcd3bc58a3 | ||
![]() |
a82f17c594 | ||
![]() |
b38fd1ca5f | ||
![]() |
8e82113bce | ||
![]() |
f723ef153b | ||
![]() |
1dc723fb6d | ||
![]() |
8f271c2575 | ||
![]() |
7cf56b4406 | ||
![]() |
c2eb603957 | ||
![]() |
e6bd2ff60f | ||
![]() |
5604074eba | ||
![]() |
3f061c1a1e | ||
![]() |
55e78a7b1a | ||
![]() |
000f1d6041 | ||
![]() |
2cbec20238 | ||
![]() |
4b724c7257 | ||
![]() |
ab04c6ab39 | ||
![]() |
821a6c6954 | ||
![]() |
5f27a62221 | ||
![]() |
c76cc4c6bd | ||
![]() |
52b75c53b6 | ||
![]() |
9db2e99086 | ||
![]() |
e9e2ecf2dd | ||
![]() |
9a9e617c35 | ||
![]() |
3a0becc783 | ||
![]() |
1f974cb220 | ||
![]() |
1db80228e8 | ||
![]() |
838e1e254d | ||
![]() |
554eda8fe1 | ||
![]() |
2bdc047c4d | ||
![]() |
e64f59ce5b | ||
![]() |
b8140ad4e6 | ||
![]() |
5a55483698 | ||
![]() |
2d341863f5 | ||
![]() |
278046becb | ||
![]() |
5c0497354f | ||
![]() |
98c258df93 | ||
![]() |
c578cccfd5 | ||
![]() |
07835a3e0e | ||
![]() |
09131aca89 | ||
![]() |
9ce998a6df | ||
![]() |
ca36b42d79 | ||
![]() |
37df39ec37 | ||
![]() |
1701361a73 | ||
![]() |
4c14ae33f5 | ||
![]() |
d4a9ef7b7f | ||
![]() |
1539cfe888 | ||
![]() |
9093be1329 | ||
![]() |
606d076251 | ||
![]() |
46a34e19bc | ||
![]() |
5ac7dc0b37 | ||
![]() |
3b27de3715 | ||
![]() |
939bfac920 | ||
![]() |
f601bf12d5 | ||
![]() |
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 |
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -12,13 +12,11 @@
|
|||||||
|
|
||||||
# Denote all files that are truly binary and should not be modified.
|
# Denote all files that are truly binary and should not be modified.
|
||||||
tools/** binary
|
tools/** binary
|
||||||
|
tools/rustup-wrapper/** -binary
|
||||||
|
tools/elf-cleaner/** -binary
|
||||||
*.jar binary
|
*.jar binary
|
||||||
*.exe binary
|
*.exe binary
|
||||||
*.apk binary
|
*.apk binary
|
||||||
*.png binary
|
*.png binary
|
||||||
*.jpg binary
|
*.jpg binary
|
||||||
*.ttf binary
|
*.ttf binary
|
||||||
|
|
||||||
# Help GitHub detect languages
|
|
||||||
native/jni/external/** linguist-vendored
|
|
||||||
native/jni/systemproperties/** linguist-language=C++
|
|
||||||
|
107
.github/actions/setup/action.yml
vendored
Normal file
107
.github/actions/setup/action.yml
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
name: Magisk Setup
|
||||||
|
inputs:
|
||||||
|
is-asset-build:
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Set up JDK 21
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: "temurin"
|
||||||
|
java-version: "21"
|
||||||
|
|
||||||
|
- name: Set up Python 3
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.x"
|
||||||
|
|
||||||
|
- name: Install GNU make
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
brew install make
|
||||||
|
echo 'GNUMAKE=gmake' >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Cache sccache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
with:
|
||||||
|
path: .sccache
|
||||||
|
key: sccache-${{ runner.os }}-${{ github.sha }}
|
||||||
|
restore-keys: sccache-${{ runner.os }}-
|
||||||
|
|
||||||
|
- name: Restore sccache
|
||||||
|
uses: actions/cache/restore@v4
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
with:
|
||||||
|
path: .sccache
|
||||||
|
key: sccache-${{ runner.os }}-${{ github.sha }}
|
||||||
|
restore-keys: sccache-${{ runner.os }}-
|
||||||
|
|
||||||
|
- name: Set up sccache
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
SCCACHE_DIRECT: false
|
||||||
|
SCCACHE_DIR: ${{ github.workspace }}/.sccache
|
||||||
|
SCCACHE_CACHE_SIZE: ${{ inputs.is-asset-build == 'true' && '2G' || '300M' }}
|
||||||
|
SCCACHE_IDLE_TIMEOUT: 0
|
||||||
|
run: |
|
||||||
|
bash $GITHUB_ACTION_PATH/sccache.sh
|
||||||
|
sccache --start-server
|
||||||
|
sccache -z
|
||||||
|
|
||||||
|
- name: Show sccache stats
|
||||||
|
uses: gacts/run-and-post-run@v1
|
||||||
|
with:
|
||||||
|
run: sccache -s
|
||||||
|
post: sccache -s
|
||||||
|
|
||||||
|
- name: Set GRADLE_USER_HOME
|
||||||
|
shell: bash
|
||||||
|
run: echo "GRADLE_USER_HOME=$GITHUB_WORKSPACE/.gradle" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Cache Gradle dependencies
|
||||||
|
uses: actions/cache@v4
|
||||||
|
if: ${{ inputs.is-asset-build == 'true' && github.event_name != 'pull_request' }}
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
.gradle/caches
|
||||||
|
.gradle/wrapper
|
||||||
|
!.gradle/caches/build-cache-*
|
||||||
|
key: gradle-cache-${{ hashFiles('app/gradle/**') }}
|
||||||
|
restore-keys: gradle-cache-
|
||||||
|
|
||||||
|
- name: Restore Gradle dependencies
|
||||||
|
uses: actions/cache/restore@v4
|
||||||
|
if: ${{ inputs.is-asset-build == 'false' || github.event_name == 'pull_request' }}
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
.gradle/caches
|
||||||
|
.gradle/wrapper
|
||||||
|
!.gradle/caches/build-cache-*
|
||||||
|
key: gradle-cache-${{ hashFiles('gradle/**') }}
|
||||||
|
restore-keys: gradle-cache-
|
||||||
|
enableCrossOsArchive: true
|
||||||
|
|
||||||
|
- name: Cache Gradle build cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
if: ${{ inputs.is-asset-build == 'true' && github.event_name != 'pull_request' }}
|
||||||
|
with:
|
||||||
|
path: .gradle/caches/build-cache-*
|
||||||
|
key: gradle-build-cache-${{ github.sha }}
|
||||||
|
restore-keys: gradle-build-cache-
|
||||||
|
|
||||||
|
- name: Restore Gradle build cache
|
||||||
|
uses: actions/cache/restore@v4
|
||||||
|
if: ${{ inputs.is-asset-build == 'false' || github.event_name == 'pull_request' }}
|
||||||
|
with:
|
||||||
|
path: .gradle/caches/build-cache-*
|
||||||
|
key: gradle-build-cache-${{ github.sha }}
|
||||||
|
restore-keys: gradle-build-cache-
|
||||||
|
enableCrossOsArchive: true
|
||||||
|
|
||||||
|
- name: Set up NDK
|
||||||
|
shell: bash
|
||||||
|
run: python build.py -v ndk
|
25
.github/actions/setup/sccache.sh
vendored
Executable file
25
.github/actions/setup/sccache.sh
vendored
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Get latest sccache version
|
||||||
|
get_sccache_ver() {
|
||||||
|
curl -sL 'https://api.github.com/repos/mozilla/sccache/releases/latest' | jq -r .name
|
||||||
|
}
|
||||||
|
|
||||||
|
# $1=variant
|
||||||
|
# $2=install_dir
|
||||||
|
# $3=exe
|
||||||
|
install_from_gh() {
|
||||||
|
local ver=$(curl -sL 'https://api.github.com/repos/mozilla/sccache/releases/latest' | jq -r .name)
|
||||||
|
local url="https://github.com/mozilla/sccache/releases/download/${ver}/sccache-${ver}-$1.tar.gz"
|
||||||
|
local dest="$2/$3"
|
||||||
|
curl -L "$url" | tar xz -O --wildcards "*/$3" > $dest
|
||||||
|
chmod +x $dest
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $RUNNER_OS = "macOS" ]; then
|
||||||
|
brew install sccache
|
||||||
|
elif [ $RUNNER_OS = "Linux" ]; then
|
||||||
|
install_from_gh x86_64-unknown-linux-musl /usr/local/bin sccache
|
||||||
|
elif [ $RUNNER_OS = "Windows" ]; then
|
||||||
|
install_from_gh x86_64-pc-windows-msvc $USERPROFILE/.cargo/bin sccache.exe
|
||||||
|
fi
|
1
.github/ci.prop
vendored
Normal file
1
.github/ci.prop
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
abiList=arm64-v8a
|
252
.github/workflows/build.yml
vendored
252
.github/workflows/build.yml
vendored
@@ -6,10 +6,7 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "app/**"
|
- "app/**"
|
||||||
- "native/**"
|
- "native/**"
|
||||||
- "stub/**"
|
|
||||||
- "buildSrc/**"
|
|
||||||
- "build.py"
|
- "build.py"
|
||||||
- "gradle.properties"
|
|
||||||
- ".github/workflows/build.yml"
|
- ".github/workflows/build.yml"
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [master]
|
branches: [master]
|
||||||
@@ -17,118 +14,191 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build on ${{ matrix.os }}
|
name: Build Magisk artifacts
|
||||||
|
runs-on: macos-15
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
steps:
|
||||||
|
- name: Check out
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: "recursive"
|
||||||
|
|
||||||
|
- name: Setup environment
|
||||||
|
uses: ./.github/actions/setup
|
||||||
|
with:
|
||||||
|
is-asset-build: true
|
||||||
|
|
||||||
|
- name: Build release
|
||||||
|
run: ./build.py -vr all
|
||||||
|
|
||||||
|
- name: Build debug
|
||||||
|
run: ./build.py -v all
|
||||||
|
|
||||||
|
- name: Stop gradle daemon
|
||||||
|
run: ./app/gradlew --stop
|
||||||
|
|
||||||
|
- name: Upload build artifact
|
||||||
|
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 }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [windows-2025, ubuntu-24.04]
|
||||||
steps:
|
steps:
|
||||||
- name: Check out
|
- name: Check out
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: "recursive"
|
submodules: "recursive"
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Setup environment
|
||||||
uses: actions/setup-java@v3
|
uses: ./.github/actions/setup
|
||||||
with:
|
|
||||||
distribution: "temurin"
|
|
||||||
java-version: "17"
|
|
||||||
|
|
||||||
- name: Set up Python 3
|
- name: Test build
|
||||||
uses: actions/setup-python@v4
|
run: python build.py -v -c .github/ci.prop all
|
||||||
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@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: Build release
|
|
||||||
run: |
|
|
||||||
python build.py -vr all
|
|
||||||
|
|
||||||
- name: Build debug
|
|
||||||
run: |
|
|
||||||
python build.py -v all
|
|
||||||
|
|
||||||
- name: Stop gradle daemon
|
- name: Stop gradle daemon
|
||||||
run: ./gradlew --stop
|
run: ./app/gradlew --stop
|
||||||
|
|
||||||
# Only upload artifacts built on Linux
|
avd-test:
|
||||||
- name: Upload build artifact
|
name: Test API ${{ matrix.version }} (x86_64)
|
||||||
if: runner.os == 'Linux'
|
runs-on: ubuntu-24.04
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ github.sha }}
|
|
||||||
path: out
|
|
||||||
|
|
||||||
- name: Upload mapping and native debug symbols
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: ${{ github.sha }}-symbols
|
|
||||||
path: app/build/outputs
|
|
||||||
|
|
||||||
test:
|
|
||||||
name: Test on ${{ matrix.api }}
|
|
||||||
runs-on: macos-latest
|
|
||||||
needs: build
|
needs: build
|
||||||
|
if: ${{ github.event_name != 'push' }}
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
api: [23, 26, 28, 29, 34]
|
version: [23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, "36.0-CANARY"]
|
||||||
|
type: [""]
|
||||||
|
include:
|
||||||
|
- version: "36.0-CANARY"
|
||||||
|
type: "google_apis_ps16k"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out
|
- name: Check out
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
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: Download build artifacts
|
- name: Download build artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.sha }}
|
name: ${{ github.sha }}
|
||||||
path: out
|
path: out
|
||||||
|
|
||||||
- name: AVD test
|
- name: Enable KVM group perms
|
||||||
run: |
|
run: |
|
||||||
brew install coreutils
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
scripts/avd_test.sh ${{ matrix.api }}
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger --name-match=kvm
|
||||||
|
|
||||||
|
- name: Run AVD test
|
||||||
|
timeout-minutes: 10
|
||||||
|
env:
|
||||||
|
AVD_TEST_LOG: 1
|
||||||
|
run: scripts/avd.sh test ${{ matrix.version }} ${{ matrix.type }}
|
||||||
|
|
||||||
|
- name: Upload logs on error
|
||||||
|
if: ${{ failure() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: "avd-logs-${{ matrix.version }}"
|
||||||
|
path: |
|
||||||
|
kernel.log
|
||||||
|
logcat.log
|
||||||
|
|
||||||
|
avd-test-32:
|
||||||
|
name: Test API ${{ matrix.version }} (x86)
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs: build
|
||||||
|
if: ${{ github.event_name != 'push' }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
version: [23, 24, 25, 26, 27, 28, 29, 30]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- 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_LOG: 1
|
||||||
|
run: scripts/avd.sh test ${{ matrix.version }}
|
||||||
|
|
||||||
|
- name: Upload logs on error
|
||||||
|
if: ${{ failure() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: "avd32-logs-${{ matrix.version }}"
|
||||||
|
path: |
|
||||||
|
kernel.log
|
||||||
|
logcat.log
|
||||||
|
|
||||||
|
cf-test:
|
||||||
|
name: Test ${{ matrix.device }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
needs: build
|
||||||
|
if: ${{ github.event_name != 'push' }}
|
||||||
|
env:
|
||||||
|
CF_HOME: /home/runner/aosp_cf_phone
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- branch: "aosp-android-latest-release"
|
||||||
|
device: "aosp_cf_x86_64_only_phone"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- 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.device }}
|
||||||
|
|
||||||
|
- name: Run Cuttlefish test
|
||||||
|
timeout-minutes: 10
|
||||||
|
run: sudo -E -u $USER scripts/cuttlefish.sh test
|
||||||
|
|
||||||
|
- name: Upload logs on error
|
||||||
|
if: ${{ failure() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: "cvd-logs-${{ matrix.device }}"
|
||||||
|
path: |
|
||||||
|
/home/runner/aosp_cf_phone/cuttlefish/instances/cvd-1/logs
|
||||||
|
/home/runner/aosp_cf_phone/cuttlefish/instances/cvd-1/cuttlefish_config.json
|
||||||
|
12
.gitignore
vendored
12
.gitignore
vendored
@@ -2,17 +2,13 @@ out
|
|||||||
*.zip
|
*.zip
|
||||||
*.jks
|
*.jks
|
||||||
*.apk
|
*.apk
|
||||||
|
*.log
|
||||||
/config.prop
|
/config.prop
|
||||||
/update.sh
|
/notes.md
|
||||||
/dict.txt
|
|
||||||
|
|
||||||
# Built binaries
|
# Built binaries
|
||||||
native/out
|
native/out
|
||||||
|
|
||||||
# Android Studio / Gradle
|
# Android Studio
|
||||||
*.iml
|
*.iml
|
||||||
.gradle
|
.idea
|
||||||
/local.properties
|
|
||||||
/.idea
|
|
||||||
/build
|
|
||||||
/captures
|
|
||||||
|
30
.gitmodules
vendored
30
.gitmodules
vendored
@@ -1,39 +1,15 @@
|
|||||||
[submodule "selinux"]
|
[submodule "selinux"]
|
||||||
path = native/src/external/selinux
|
path = native/src/external/selinux
|
||||||
url = https://github.com/topjohnwu/selinux.git
|
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"]
|
[submodule "lz4"]
|
||||||
path = native/src/external/lz4
|
path = native/src/external/lz4
|
||||||
url = https://github.com/lz4/lz4.git
|
url = https://github.com/lz4/lz4.git
|
||||||
[submodule "bzip2"]
|
|
||||||
path = native/src/external/bzip2
|
|
||||||
url = https://github.com/nemequ/bzip2.git
|
|
||||||
[submodule "xz"]
|
[submodule "xz"]
|
||||||
path = native/src/external/xz
|
path = native/src/external/xz
|
||||||
url = https://github.com/xz-mirror/xz.git
|
url = https://github.com/xz-mirror/xz.git
|
||||||
[submodule "nanopb"]
|
|
||||||
path = native/src/external/nanopb
|
|
||||||
url = https://github.com/nanopb/nanopb.git
|
|
||||||
[submodule "pcre"]
|
|
||||||
path = native/src/external/pcre
|
|
||||||
url = https://android.googlesource.com/platform/external/pcre
|
|
||||||
[submodule "libcxx"]
|
[submodule "libcxx"]
|
||||||
path = native/src/external/libcxx
|
path = native/src/external/libcxx
|
||||||
url = https://github.com/topjohnwu/libcxx.git
|
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
|
|
||||||
[submodule "cxx-rs"]
|
[submodule "cxx-rs"]
|
||||||
path = native/src/external/cxx-rs
|
path = native/src/external/cxx-rs
|
||||||
url = https://github.com/topjohnwu/cxx.git
|
url = https://github.com/topjohnwu/cxx.git
|
||||||
@@ -43,6 +19,6 @@
|
|||||||
[submodule "system_properties"]
|
[submodule "system_properties"]
|
||||||
path = native/src/external/system_properties
|
path = native/src/external/system_properties
|
||||||
url = https://github.com/topjohnwu/system_properties.git
|
url = https://github.com/topjohnwu/system_properties.git
|
||||||
[submodule "termux-elf-cleaner"]
|
[submodule "crt0"]
|
||||||
path = tools/termux-elf-cleaner
|
path = native/src/external/crt0
|
||||||
url = https://github.com/termux/termux-elf-cleaner.git
|
url = https://github.com/topjohnwu/crt0.git
|
||||||
|
12
README.MD
12
README.MD
@@ -16,18 +16,14 @@ Some highlight features:
|
|||||||
|
|
||||||
## Downloads
|
## Downloads
|
||||||
|
|
||||||
[Github](https://github.com/topjohnwu/Magisk/) is the only source where you can get official Magisk information and downloads.
|
[Github](https://github.com/topjohnwu/Magisk/releases) is the only source where you can get official Magisk information and downloads.
|
||||||
|
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v26.1)
|
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v26.1)
|
|
||||||
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-release.apk)
|
|
||||||
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-debug.apk)
|
|
||||||
|
|
||||||
## Useful Links
|
## Useful Links
|
||||||
|
|
||||||
- [Installation Instruction](https://topjohnwu.github.io/Magisk/install.html)
|
- [Installation Instruction](https://topjohnwu.github.io/Magisk/install.html)
|
||||||
- [Building and Development](https://topjohnwu.github.io/Magisk/build.html)
|
- [Building and Development](https://topjohnwu.github.io/Magisk/build.html)
|
||||||
- [Magisk Documentation](https://topjohnwu.github.io/Magisk/)
|
- [Magisk Documentation](https://topjohnwu.github.io/Magisk/)
|
||||||
|
- [Zygisk module sample](https://github.com/topjohnwu/zygisk-module-sample)
|
||||||
|
|
||||||
## Bug Reports
|
## Bug Reports
|
||||||
|
|
||||||
@@ -41,8 +37,8 @@ For Magisk app crashes, record and upload the logcat when the crash occurs.
|
|||||||
|
|
||||||
Default string resources for the Magisk app and its stub APK are located here:
|
Default string resources for the Magisk app and its stub APK are located here:
|
||||||
|
|
||||||
- `app/src/main/res/values/strings.xml`
|
- `app/core/src/main/res/values/strings.xml`
|
||||||
- `stub/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`).
|
Translate each and place them in the respective locations (`[module]/src/main/res/values-[lang]/strings.xml`).
|
||||||
|
|
||||||
|
12
app/.gitignore
vendored
12
app/.gitignore
vendored
@@ -1,11 +1,7 @@
|
|||||||
*.iml
|
/dict.txt
|
||||||
|
|
||||||
|
# Gradle
|
||||||
.gradle
|
.gradle
|
||||||
|
.kotlin
|
||||||
/local.properties
|
/local.properties
|
||||||
.idea/
|
|
||||||
/build
|
/build
|
||||||
*.hprof
|
|
||||||
.externalNativeBuild/
|
|
||||||
*.apk
|
|
||||||
src/*/assets
|
|
||||||
src/*/jniLibs
|
|
||||||
src/*/resources
|
|
||||||
|
59
app/apk/build.gradle.kts
Normal file
59
app/apk/build.gradle.kts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.android.application")
|
||||||
|
kotlin("android")
|
||||||
|
kotlin("plugin.parcelize")
|
||||||
|
kotlin("kapt")
|
||||||
|
id("androidx.navigation.safeargs.kotlin")
|
||||||
|
}
|
||||||
|
|
||||||
|
setupMainApk()
|
||||||
|
|
||||||
|
kapt {
|
||||||
|
correctErrorTypes = true
|
||||||
|
useBuildCache = true
|
||||||
|
mapDiagnosticLocations = true
|
||||||
|
javacOptions {
|
||||||
|
option("-Xmaxerrs", "1000")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
buildFeatures {
|
||||||
|
dataBinding = true
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
isCoreLibraryDesugaringEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = true
|
||||||
|
isShrinkResources = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":core"))
|
||||||
|
coreLibraryDesugaring(libs.jdk.libs)
|
||||||
|
|
||||||
|
implementation(libs.indeterminate.checkbox)
|
||||||
|
implementation(libs.rikka.layoutinflater)
|
||||||
|
implementation(libs.rikka.insets)
|
||||||
|
implementation(libs.rikka.recyclerview)
|
||||||
|
|
||||||
|
implementation(libs.navigation.fragment.ktx)
|
||||||
|
implementation(libs.navigation.ui.ktx)
|
||||||
|
|
||||||
|
implementation(libs.constraintlayout)
|
||||||
|
implementation(libs.swiperefreshlayout)
|
||||||
|
implementation(libs.recyclerview)
|
||||||
|
implementation(libs.transition)
|
||||||
|
implementation(libs.fragment.ktx)
|
||||||
|
implementation(libs.appcompat)
|
||||||
|
implementation(libs.material)
|
||||||
|
|
||||||
|
// 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>
|
@@ -1,6 +1,8 @@
|
|||||||
package com.topjohnwu.magisk.arch
|
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.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.databinding.PropertyChangeRegistry
|
import androidx.databinding.PropertyChangeRegistry
|
||||||
@@ -8,7 +10,7 @@ import androidx.lifecycle.LiveData
|
|||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.navigation.NavDirections
|
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.databinding.ObservableHost
|
||||||
import com.topjohnwu.magisk.events.BackPressEvent
|
import com.topjohnwu.magisk.events.BackPressEvent
|
||||||
import com.topjohnwu.magisk.events.DialogBuilder
|
import com.topjohnwu.magisk.events.DialogBuilder
|
@@ -1,10 +1,13 @@
|
|||||||
package com.topjohnwu.magisk.arch
|
package com.topjohnwu.magisk.arch
|
||||||
|
|
||||||
|
import android.content.ContentResolver
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import androidx.databinding.ViewDataBinding
|
import androidx.databinding.ViewDataBinding
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavDirections
|
import androidx.navigation.NavDirections
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import androidx.navigation.navOptions
|
||||||
|
import com.topjohnwu.magisk.utils.AccessibilityUtils
|
||||||
|
|
||||||
abstract class NavigationActivity<Binding : ViewDataBinding> : UIActivity<Binding>() {
|
abstract class NavigationActivity<Binding : ViewDataBinding> : UIActivity<Binding>() {
|
||||||
|
|
||||||
@@ -31,7 +34,17 @@ abstract class NavigationActivity<Binding : ViewDataBinding> : UIActivity<Bindin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun navigate(directions: NavDirections, navigation: NavController, cr: ContentResolver) {
|
||||||
|
if (AccessibilityUtils.isAnimationEnabled(cr)) {
|
||||||
|
navigation.navigate(directions)
|
||||||
|
} else {
|
||||||
|
navigation.navigate(directions, navOptions {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun NavDirections.navigate() {
|
fun NavDirections.navigate() {
|
||||||
navigation.navigate(this)
|
navigate(this, navigation, contentResolver)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,11 +1,13 @@
|
|||||||
package com.topjohnwu.magisk.arch
|
package com.topjohnwu.magisk.arch
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.core.content.res.use
|
import androidx.core.content.res.use
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
@@ -18,14 +20,20 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.Config
|
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.insets.WindowInsetsHelper
|
||||||
import rikka.layoutinflater.view.LayoutInflaterFactory
|
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 lateinit var binding: Binding
|
||||||
protected abstract val layoutRes: Int
|
protected abstract val layoutRes: Int
|
||||||
|
override val extension = ActivityExtension(this)
|
||||||
|
|
||||||
protected val binded get() = ::binding.isInitialized
|
protected val binded get() = ::binding.isInitialized
|
||||||
|
|
||||||
@@ -36,10 +44,23 @@ abstract class UIActivity<Binding : ViewDataBinding> : BaseActivity(), ViewModel
|
|||||||
AppCompatDelegate.setDefaultNightMode(Config.darkTheme)
|
AppCompatDelegate.setDefaultNightMode(Config.darkTheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun attachBaseContext(base: Context) {
|
||||||
|
super.attachBaseContext(base.wrap())
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
layoutInflater.factory2 = LayoutInflaterFactory(delegate)
|
layoutInflater.factory2 = LayoutInflaterFactory(delegate)
|
||||||
.addOnViewCreatedListener(WindowInsetsHelper.LISTENER)
|
.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)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
startObserveLiveData()
|
startObserveLiveData()
|
||||||
@@ -70,6 +91,11 @@ abstract class UIActivity<Binding : ViewDataBinding> : BaseActivity(), ViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
extension.onSaveInstanceState(outState)
|
||||||
|
}
|
||||||
|
|
||||||
fun setContentView() {
|
fun setContentView() {
|
||||||
binding = DataBindingUtil.setContentView<Binding>(this, layoutRes).also {
|
binding = DataBindingUtil.setContentView<Binding>(this, layoutRes).also {
|
||||||
it.setVariable(BR.viewModel, viewModel)
|
it.setVariable(BR.viewModel, viewModel)
|
@@ -8,7 +8,12 @@ import android.text.Spanned
|
|||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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.annotation.DrawableRes
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
@@ -19,14 +24,21 @@ import androidx.core.widget.ImageViewCompat
|
|||||||
import androidx.databinding.BindingAdapter
|
import androidx.databinding.BindingAdapter
|
||||||
import androidx.databinding.InverseBindingAdapter
|
import androidx.databinding.InverseBindingAdapter
|
||||||
import androidx.databinding.InverseBindingListener
|
import androidx.databinding.InverseBindingListener
|
||||||
|
import androidx.databinding.InverseMethod
|
||||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
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.button.MaterialButton
|
||||||
import com.google.android.material.card.MaterialCardView
|
import com.google.android.material.card.MaterialCardView
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
|
import com.google.android.material.slider.Slider
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||||
|
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||||
import com.topjohnwu.magisk.utils.TextHolder
|
import com.topjohnwu.magisk.utils.TextHolder
|
||||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
import com.topjohnwu.widget.IndeterminateCheckBox
|
import com.topjohnwu.widget.IndeterminateCheckBox
|
||||||
@@ -297,3 +309,38 @@ fun TextView.setText(text: TextHolder) {
|
|||||||
fun Spinner.setAdapter(items: Array<Any>, layoutRes: Int) {
|
fun Spinner.setAdapter(items: Array<Any>, layoutRes: Int) {
|
||||||
adapter = ArrayAdapter(context, layoutRes, items)
|
adapter = ArrayAdapter(context, layoutRes, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("labelFormatter")
|
||||||
|
fun Slider.setLabelFormatter(formatter: (Float) -> Int) {
|
||||||
|
setLabelFormatter { value -> resources.getString(formatter(value)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@InverseBindingAdapter(attribute = "android:value")
|
||||||
|
fun Slider.getValueBinding() = value
|
||||||
|
|
||||||
|
@BindingAdapter("android:valueAttrChanged")
|
||||||
|
fun Slider.setListener(attrChange: InverseBindingListener) {
|
||||||
|
addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
|
||||||
|
override fun onStartTrackingTouch(slider: Slider) = Unit
|
||||||
|
override fun onStopTrackingTouch(slider: Slider) = attrChange.onChange()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@InverseMethod("sliderValueToPolicy")
|
||||||
|
fun policyToSliderValue(policy: Int): Float {
|
||||||
|
return when (policy) {
|
||||||
|
SuPolicy.DENY -> 1f
|
||||||
|
SuPolicy.RESTRICT -> 2f
|
||||||
|
SuPolicy.ALLOW -> 3f
|
||||||
|
else -> 1f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sliderValueToPolicy(value: Float): Int {
|
||||||
|
return when (value) {
|
||||||
|
1f -> SuPolicy.DENY
|
||||||
|
2f -> SuPolicy.RESTRICT
|
||||||
|
3f -> SuPolicy.ALLOW
|
||||||
|
else -> SuPolicy.DENY
|
||||||
|
}
|
||||||
|
}
|
@@ -3,7 +3,7 @@ package com.topjohnwu.magisk.databinding
|
|||||||
import androidx.databinding.ListChangeRegistry
|
import androidx.databinding.ListChangeRegistry
|
||||||
import androidx.databinding.ObservableList
|
import androidx.databinding.ObservableList
|
||||||
import androidx.databinding.ObservableList.OnListChangedCallback
|
import androidx.databinding.ObservableList.OnListChangedCallback
|
||||||
import java.util.*
|
import java.util.AbstractList
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
class MergeObservableList<T> : AbstractList<T>(), ObservableList<T> {
|
class MergeObservableList<T> : AbstractList<T>(), ObservableList<T> {
|
@@ -7,26 +7,27 @@ import com.topjohnwu.magisk.arch.UIActivity
|
|||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.events.DialogBuilder
|
import com.topjohnwu.magisk.events.DialogBuilder
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class DarkThemeDialog : DialogBuilder {
|
class DarkThemeDialog : DialogBuilder {
|
||||||
|
|
||||||
override fun build(dialog: MagiskDialog) {
|
override fun build(dialog: MagiskDialog) {
|
||||||
val activity = dialog.ownerActivity!!
|
val activity = dialog.ownerActivity!!
|
||||||
dialog.apply {
|
dialog.apply {
|
||||||
setTitle(R.string.settings_dark_mode_title)
|
setTitle(CoreR.string.settings_dark_mode_title)
|
||||||
setMessage(R.string.settings_dark_mode_message)
|
setMessage(CoreR.string.settings_dark_mode_message)
|
||||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||||
text = R.string.settings_dark_mode_light
|
text = CoreR.string.settings_dark_mode_light
|
||||||
icon = R.drawable.ic_day
|
icon = R.drawable.ic_day
|
||||||
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_NO, activity) }
|
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_NO, activity) }
|
||||||
}
|
}
|
||||||
setButton(MagiskDialog.ButtonType.NEUTRAL) {
|
setButton(MagiskDialog.ButtonType.NEUTRAL) {
|
||||||
text = R.string.settings_dark_mode_system
|
text = CoreR.string.settings_dark_mode_system
|
||||||
icon = R.drawable.ic_day_night
|
icon = R.drawable.ic_day_night
|
||||||
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM, activity) }
|
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM, activity) }
|
||||||
}
|
}
|
||||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||||
text = R.string.settings_dark_mode_dark
|
text = CoreR.string.settings_dark_mode_dark
|
||||||
icon = R.drawable.ic_night
|
icon = R.drawable.ic_night
|
||||||
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_YES, activity) }
|
onClick { selectTheme(AppCompatDelegate.MODE_NIGHT_YES, activity) }
|
||||||
}
|
}
|
@@ -1,14 +1,18 @@
|
|||||||
package com.topjohnwu.magisk.dialog
|
package com.topjohnwu.magisk.dialog
|
||||||
|
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.os.postDelayed
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.topjohnwu.magisk.BuildConfig
|
import com.topjohnwu.magisk.core.BuildConfig
|
||||||
import com.topjohnwu.magisk.R
|
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
import com.topjohnwu.magisk.core.R
|
||||||
|
import com.topjohnwu.magisk.core.ktx.reboot
|
||||||
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
||||||
import com.topjohnwu.magisk.events.DialogBuilder
|
import com.topjohnwu.magisk.events.DialogBuilder
|
||||||
import com.topjohnwu.magisk.ui.home.HomeViewModel
|
import com.topjohnwu.magisk.ui.home.HomeViewModel
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : DialogBuilder {
|
class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : DialogBuilder {
|
||||||
@@ -27,10 +31,16 @@ class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : Dialo
|
|||||||
resetButtons()
|
resetButtons()
|
||||||
setCancelable(false)
|
setCancelable(false)
|
||||||
}
|
}
|
||||||
(dialog.ownerActivity as BaseActivity).lifecycleScope.launch {
|
dialog.activity.lifecycleScope.launch {
|
||||||
MagiskInstaller.FixEnv {
|
MagiskInstaller.FixEnv().exec { success ->
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}.exec()
|
context.toast(
|
||||||
|
if (success) R.string.reboot_delay_toast else R.string.setup_fail,
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
)
|
||||||
|
if (success)
|
||||||
|
UiThreadHandler.handler.postDelayed(5000) { reboot() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,8 +50,8 @@ class EnvFixDialog(private val vm: HomeViewModel, private val code: Int) : Dialo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (code == 2 || // No rules block, module policy not loaded
|
if (code == 2 || // No rules block, module policy not loaded
|
||||||
Info.env.versionCode != BuildConfig.VERSION_CODE ||
|
Info.env.versionCode != BuildConfig.APP_VERSION_CODE ||
|
||||||
Info.env.versionString != BuildConfig.VERSION_NAME) {
|
Info.env.versionString != BuildConfig.APP_VERSION_NAME) {
|
||||||
dialog.setMessage(R.string.env_full_fix_msg)
|
dialog.setMessage(R.string.env_full_fix_msg)
|
||||||
dialog.setButton(MagiskDialog.ButtonType.POSITIVE) {
|
dialog.setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||||
text = android.R.string.ok
|
text = android.R.string.ok
|
@@ -2,8 +2,8 @@ package com.topjohnwu.magisk.dialog
|
|||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.topjohnwu.magisk.MainDirections
|
import com.topjohnwu.magisk.MainDirections
|
||||||
import com.topjohnwu.magisk.R
|
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
|
import com.topjohnwu.magisk.core.R
|
||||||
import com.topjohnwu.magisk.events.DialogBuilder
|
import com.topjohnwu.magisk.events.DialogBuilder
|
||||||
import com.topjohnwu.magisk.ui.module.ModuleViewModel
|
import com.topjohnwu.magisk.ui.module.ModuleViewModel
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
@@ -1,25 +1,19 @@
|
|||||||
package com.topjohnwu.magisk.dialog
|
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.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.DownloadEngine
|
||||||
import com.topjohnwu.magisk.core.download.DownloadService
|
|
||||||
import com.topjohnwu.magisk.core.download.Subject
|
import com.topjohnwu.magisk.core.download.Subject
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class ManagerInstallDialog : MarkDownDialog() {
|
class ManagerInstallDialog : MarkDownDialog() {
|
||||||
|
|
||||||
private val svc get() = ServiceLocator.networkService
|
|
||||||
|
|
||||||
override suspend fun getMarkdownText(): String {
|
override suspend fun getMarkdownText(): String {
|
||||||
val text = svc.fetchString(Info.remote.magisk.note)
|
val text = Info.update.note
|
||||||
// Cache the changelog
|
// Cache the changelog
|
||||||
AppContext.cacheDir.listFiles { _, name -> name.endsWith(".md") }.orEmpty().forEach {
|
File(AppContext.cacheDir, "${Info.update.versionCode}.md").writeText(text)
|
||||||
it.delete()
|
|
||||||
}
|
|
||||||
File(AppContext.cacheDir, "${Info.remote.magisk.versionCode}.md").writeText(text)
|
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +23,7 @@ class ManagerInstallDialog : MarkDownDialog() {
|
|||||||
setCancelable(true)
|
setCancelable(true)
|
||||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||||
text = R.string.install
|
text = R.string.install
|
||||||
onClick { DownloadService.start(activity, Subject.App()) }
|
onClick { DownloadEngine.startWithActivity(activity, Subject.App()) }
|
||||||
}
|
}
|
||||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||||
text = android.R.string.cancel
|
text = android.R.string.cancel
|
@@ -13,6 +13,7 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
abstract class MarkDownDialog : DialogBuilder {
|
abstract class MarkDownDialog : DialogBuilder {
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ abstract class MarkDownDialog : DialogBuilder {
|
|||||||
ServiceLocator.markwon.setMarkdown(tv, text)
|
ServiceLocator.markwon.setMarkdown(tv, text)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
tv.setText(R.string.download_file_error)
|
tv.setText(CoreR.string.download_file_error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,12 +1,15 @@
|
|||||||
package com.topjohnwu.magisk.dialog
|
package com.topjohnwu.magisk.dialog
|
||||||
|
|
||||||
import com.topjohnwu.magisk.R
|
import android.content.Context
|
||||||
|
import com.topjohnwu.magisk.core.R
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||||
import com.topjohnwu.magisk.core.download.Action
|
import com.topjohnwu.magisk.core.download.DownloadEngine
|
||||||
import com.topjohnwu.magisk.core.download.DownloadService
|
|
||||||
import com.topjohnwu.magisk.core.download.Subject
|
import com.topjohnwu.magisk.core.download.Subject
|
||||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||||
|
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
|
import com.topjohnwu.magisk.view.Notifications
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog() {
|
class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog() {
|
||||||
|
|
||||||
@@ -17,14 +20,21 @@ class OnlineModuleInstallDialog(private val item: OnlineModule) : MarkDownDialog
|
|||||||
return if (str.length > 1000) str.substring(0, 1000) else str
|
return if (str.length > 1000) str.substring(0, 1000) else str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
class Module(
|
||||||
|
override val module: OnlineModule,
|
||||||
|
override val autoLaunch: Boolean,
|
||||||
|
override val notifyId: Int = Notifications.nextId()
|
||||||
|
) : Subject.Module() {
|
||||||
|
override fun pendingIntent(context: Context) = FlashFragment.installIntent(context, file)
|
||||||
|
}
|
||||||
|
|
||||||
override fun build(dialog: MagiskDialog) {
|
override fun build(dialog: MagiskDialog) {
|
||||||
super.build(dialog)
|
super.build(dialog)
|
||||||
dialog.apply {
|
dialog.apply {
|
||||||
|
|
||||||
fun download(install: Boolean) {
|
fun download(install: Boolean) {
|
||||||
val action = if (install) Action.Flash else Action.Download
|
DownloadEngine.startWithActivity(activity, Module(item, install))
|
||||||
val subject = Subject.Module(item, action)
|
|
||||||
DownloadService.start(activity, subject)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val title = context.getString(R.string.repo_install_title,
|
val title = context.getString(R.string.repo_install_title,
|
@@ -1,6 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.dialog
|
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.events.DialogBuilder
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
|
|
@@ -1,6 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.dialog
|
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.events.DialogBuilder
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
|
|
@@ -1,15 +1,17 @@
|
|||||||
package com.topjohnwu.magisk.dialog
|
package com.topjohnwu.magisk.dialog
|
||||||
|
|
||||||
import android.app.ProgressDialog
|
import android.app.ProgressDialog
|
||||||
import android.content.Context
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.topjohnwu.magisk.R
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.topjohnwu.magisk.arch.NavigationActivity
|
import com.topjohnwu.magisk.arch.NavigationActivity
|
||||||
|
import com.topjohnwu.magisk.arch.UIActivity
|
||||||
|
import com.topjohnwu.magisk.core.R
|
||||||
import com.topjohnwu.magisk.core.ktx.toast
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
|
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
||||||
import com.topjohnwu.magisk.events.DialogBuilder
|
import com.topjohnwu.magisk.events.DialogBuilder
|
||||||
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
import com.topjohnwu.superuser.Shell
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class UninstallDialog : DialogBuilder {
|
class UninstallDialog : DialogBuilder {
|
||||||
|
|
||||||
@@ -19,7 +21,7 @@ class UninstallDialog : DialogBuilder {
|
|||||||
setMessage(R.string.uninstall_magisk_msg)
|
setMessage(R.string.uninstall_magisk_msg)
|
||||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||||
text = R.string.restore_img
|
text = R.string.restore_img
|
||||||
onClick { restore(dialog.context) }
|
onClick { restore(dialog.activity) }
|
||||||
}
|
}
|
||||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||||
text = R.string.complete_uninstall
|
text = R.string.complete_uninstall
|
||||||
@@ -29,18 +31,20 @@ class UninstallDialog : DialogBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
private fun restore(context: Context) {
|
private fun restore(activity: UIActivity<*>) {
|
||||||
val dialog = ProgressDialog(context).apply {
|
val dialog = ProgressDialog(activity).apply {
|
||||||
setMessage(context.getString(R.string.restore_img_msg))
|
setMessage(activity.getString(R.string.restore_img_msg))
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
|
|
||||||
Shell.cmd("restore_imgs").submit { result ->
|
activity.lifecycleScope.launch {
|
||||||
dialog.dismiss()
|
MagiskInstaller.Restore().exec { success ->
|
||||||
if (result.isSuccess) {
|
dialog.dismiss()
|
||||||
context.toast(R.string.restore_done, Toast.LENGTH_SHORT)
|
if (success) {
|
||||||
} else {
|
activity.toast(R.string.restore_done, Toast.LENGTH_SHORT)
|
||||||
context.toast(R.string.restore_fail, Toast.LENGTH_LONG)
|
} else {
|
||||||
|
activity.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.UIActivity
|
||||||
import com.topjohnwu.magisk.arch.ViewEvent
|
import com.topjohnwu.magisk.arch.ViewEvent
|
||||||
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
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.TextHolder
|
||||||
import com.topjohnwu.magisk.utils.asText
|
import com.topjohnwu.magisk.utils.asText
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
@@ -47,7 +48,16 @@ class ShowUIEvent(private val delegate: View.AccessibilityDelegate?)
|
|||||||
|
|
||||||
class RecreateEvent : ViewEvent(), ActivityExecutor {
|
class RecreateEvent : ViewEvent(), ActivityExecutor {
|
||||||
override fun invoke(activity: UIActivity<*>) {
|
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
|
package com.topjohnwu.magisk.ui
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
@@ -8,6 +9,7 @@ import android.os.Bundle
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.view.forEach
|
import androidx.core.view.forEach
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
@@ -17,29 +19,35 @@ import androidx.navigation.NavDirections
|
|||||||
import com.topjohnwu.magisk.MainDirections
|
import com.topjohnwu.magisk.MainDirections
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||||
|
import com.topjohnwu.magisk.arch.NavigationActivity
|
||||||
import com.topjohnwu.magisk.arch.startAnimations
|
import com.topjohnwu.magisk.arch.startAnimations
|
||||||
import com.topjohnwu.magisk.arch.viewModel
|
import com.topjohnwu.magisk.arch.viewModel
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.core.Info
|
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.isRunningAsStub
|
||||||
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
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.databinding.ActivityMainMd2Binding
|
||||||
import com.topjohnwu.magisk.ui.home.HomeFragmentDirections
|
import com.topjohnwu.magisk.ui.home.HomeFragmentDirections
|
||||||
|
import com.topjohnwu.magisk.ui.theme.Theme
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
import com.topjohnwu.magisk.view.Shortcuts
|
import com.topjohnwu.magisk.view.Shortcuts
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class MainViewModel : BaseViewModel()
|
class MainViewModel : BaseViewModel()
|
||||||
|
|
||||||
class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
class MainActivity : NavigationActivity<ActivityMainMd2Binding>(), SplashScreenHost {
|
||||||
|
|
||||||
override val layoutRes = R.layout.activity_main_md2
|
override val layoutRes = R.layout.activity_main_md2
|
||||||
override val viewModel by viewModel<MainViewModel>()
|
override val viewModel by viewModel<MainViewModel>()
|
||||||
override val navHostId: Int = R.id.main_nav_host
|
override val navHostId: Int = R.id.main_nav_host
|
||||||
|
override val splashController = SplashController(this)
|
||||||
override val snackbarView: View
|
override val snackbarView: View
|
||||||
get() {
|
get() {
|
||||||
val fragmentOverride = currentFragment?.snackbarView
|
val fragmentOverride = currentFragment?.snackbarView
|
||||||
@@ -57,12 +65,23 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
|||||||
|
|
||||||
private var isRootFragment = true
|
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")
|
@SuppressLint("InlinedApi")
|
||||||
override fun showMainUI(savedInstanceState: Bundle?) {
|
override fun onCreateUi(savedInstanceState: Bundle?) {
|
||||||
setContentView()
|
setContentView()
|
||||||
showUnsupportedMessage()
|
showUnsupportedMessage()
|
||||||
askForHomeShortcut()
|
askForHomeShortcut()
|
||||||
checkStubComponent()
|
|
||||||
|
|
||||||
// Ask permission to post notifications for background update check
|
// Ask permission to post notifications for background update check
|
||||||
if (Config.checkUpdate) {
|
if (Config.checkUpdate) {
|
||||||
@@ -169,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() {
|
private fun showUnsupportedMessage() {
|
||||||
if (Info.env.isUnsupported) {
|
if (Info.env.isUnsupported) {
|
||||||
MagiskDialog(this).apply {
|
MagiskDialog(this).apply {
|
||||||
setTitle(R.string.unsupport_magisk_title)
|
setTitle(CoreR.string.unsupport_magisk_title)
|
||||||
setMessage(R.string.unsupport_magisk_msg, Const.Version.MIN_VERSION)
|
setMessage(CoreR.string.unsupport_magisk_msg, Const.Version.MIN_VERSION)
|
||||||
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
||||||
setCancelable(false)
|
setCancelable(false)
|
||||||
}.show()
|
}.show()
|
||||||
@@ -184,8 +228,8 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
|||||||
?.filterNot { File("$it/magisk").exists() }
|
?.filterNot { File("$it/magisk").exists() }
|
||||||
?.any { File("$it/su").exists() } == true) {
|
?.any { File("$it/su").exists() } == true) {
|
||||||
MagiskDialog(this).apply {
|
MagiskDialog(this).apply {
|
||||||
setTitle(R.string.unsupport_general_title)
|
setTitle(CoreR.string.unsupport_general_title)
|
||||||
setMessage(R.string.unsupport_other_su_msg)
|
setMessage(CoreR.string.unsupport_other_su_msg)
|
||||||
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
||||||
setCancelable(false)
|
setCancelable(false)
|
||||||
}.show()
|
}.show()
|
||||||
@@ -193,8 +237,8 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
|||||||
|
|
||||||
if (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) {
|
if (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) {
|
||||||
MagiskDialog(this).apply {
|
MagiskDialog(this).apply {
|
||||||
setTitle(R.string.unsupport_general_title)
|
setTitle(CoreR.string.unsupport_general_title)
|
||||||
setMessage(R.string.unsupport_system_app_msg)
|
setMessage(CoreR.string.unsupport_system_app_msg)
|
||||||
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
||||||
setCancelable(false)
|
setCancelable(false)
|
||||||
}.show()
|
}.show()
|
||||||
@@ -202,8 +246,8 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
|||||||
|
|
||||||
if (applicationInfo.flags and ApplicationInfo.FLAG_EXTERNAL_STORAGE != 0) {
|
if (applicationInfo.flags and ApplicationInfo.FLAG_EXTERNAL_STORAGE != 0) {
|
||||||
MagiskDialog(this).apply {
|
MagiskDialog(this).apply {
|
||||||
setTitle(R.string.unsupport_general_title)
|
setTitle(CoreR.string.unsupport_general_title)
|
||||||
setMessage(R.string.unsupport_external_storage_msg)
|
setMessage(CoreR.string.unsupport_external_storage_msg)
|
||||||
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
setButton(MagiskDialog.ButtonType.POSITIVE) { text = android.R.string.ok }
|
||||||
setCancelable(false)
|
setCancelable(false)
|
||||||
}.show()
|
}.show()
|
||||||
@@ -216,8 +260,8 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
|||||||
// Ask and show dialog
|
// Ask and show dialog
|
||||||
Config.askedHome = true
|
Config.askedHome = true
|
||||||
MagiskDialog(this).apply {
|
MagiskDialog(this).apply {
|
||||||
setTitle(R.string.add_shortcut_title)
|
setTitle(CoreR.string.add_shortcut_title)
|
||||||
setMessage(R.string.add_shortcut_msg)
|
setMessage(CoreR.string.add_shortcut_msg)
|
||||||
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
setButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||||
text = android.R.string.cancel
|
text = android.R.string.cancel
|
||||||
}
|
}
|
||||||
@@ -231,22 +275,4 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
|
|||||||
}.show()
|
}.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.ApplicationInfo
|
||||||
import android.content.pm.ComponentInfo
|
import android.content.pm.ComponentInfo
|
||||||
import android.content.pm.PackageManager
|
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.content.pm.ServiceInfo
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Build.VERSION.SDK_INT
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import androidx.core.os.ProcessCompat
|
import androidx.core.os.ProcessCompat
|
||||||
import com.topjohnwu.magisk.core.ktx.getLabel
|
import com.topjohnwu.magisk.core.ktx.getLabel
|
||||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
import java.util.Locale
|
||||||
import java.util.*
|
import java.util.TreeSet
|
||||||
|
|
||||||
class CmdlineListItem(line: String) {
|
class CmdlineListItem(line: String) {
|
||||||
val packageName: String
|
val packageName: String
|
||||||
@@ -97,7 +102,7 @@ class AppProcessInfo(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val comparator = compareBy<AppProcessInfo>(
|
private val comparator = compareBy<AppProcessInfo>(
|
||||||
{ it.label.lowercase(currentLocale) },
|
{ it.label.lowercase(Locale.ROOT) },
|
||||||
{ it.info.packageName }
|
{ it.info.packageName }
|
||||||
)
|
)
|
||||||
}
|
}
|
@@ -16,6 +16,7 @@ import com.topjohnwu.magisk.databinding.FragmentDenyMd2Binding
|
|||||||
import rikka.recyclerview.addEdgeSpacing
|
import rikka.recyclerview.addEdgeSpacing
|
||||||
import rikka.recyclerview.addItemSpacing
|
import rikka.recyclerview.addItemSpacing
|
||||||
import rikka.recyclerview.fixEdgeEffect
|
import rikka.recyclerview.fixEdgeEffect
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>(), MenuProvider {
|
class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>(), MenuProvider {
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>(), MenuProvider {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.setTitle(R.string.denylist)
|
activity?.setTitle(CoreR.string.denylist)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
@@ -58,7 +59,7 @@ class DenyListFragment : BaseFragment<FragmentDenyMd2Binding>(), MenuProvider {
|
|||||||
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater.inflate(R.menu.menu_deny_md2, menu)
|
inflater.inflate(R.menu.menu_deny_md2, menu)
|
||||||
searchView = menu.findItem(R.id.action_search).actionView as SearchView
|
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 {
|
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||||
override fun onQueryTextSubmit(query: String?): Boolean {
|
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||||
viewModel.query = query ?: ""
|
viewModel.query = query ?: ""
|
@@ -6,7 +6,7 @@ import androidx.databinding.Bindable
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
import com.topjohnwu.magisk.core.AppContext
|
||||||
import com.topjohnwu.magisk.core.ktx.concurrentMap
|
import com.topjohnwu.magisk.core.ktx.concurrentMap
|
||||||
import com.topjohnwu.magisk.databinding.bindExtra
|
import com.topjohnwu.magisk.databinding.bindExtra
|
||||||
import com.topjohnwu.magisk.databinding.filterList
|
import com.topjohnwu.magisk.databinding.filterList
|
@@ -5,7 +5,11 @@ import android.content.Context
|
|||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
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.MenuProvider
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.navigation.NavDeepLinkBuilder
|
import androidx.navigation.NavDeepLinkBuilder
|
||||||
@@ -17,6 +21,7 @@ import com.topjohnwu.magisk.core.Const
|
|||||||
import com.topjohnwu.magisk.core.cmp
|
import com.topjohnwu.magisk.core.cmp
|
||||||
import com.topjohnwu.magisk.databinding.FragmentFlashMd2Binding
|
import com.topjohnwu.magisk.databinding.FragmentFlashMd2Binding
|
||||||
import com.topjohnwu.magisk.ui.MainActivity
|
import com.topjohnwu.magisk.ui.MainActivity
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class FlashFragment : BaseFragment<FragmentFlashMd2Binding>(), MenuProvider {
|
class FlashFragment : BaseFragment<FragmentFlashMd2Binding>(), MenuProvider {
|
||||||
|
|
||||||
@@ -35,14 +40,14 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>(), MenuProvider {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.setTitle(R.string.flash_screen_title)
|
activity?.setTitle(CoreR.string.flash_screen_title)
|
||||||
|
|
||||||
viewModel.state.observe(this) {
|
viewModel.state.observe(this) {
|
||||||
activity?.supportActionBar?.setSubtitle(
|
activity?.supportActionBar?.setSubtitle(
|
||||||
when (it) {
|
when (it) {
|
||||||
FlashViewModel.State.FLASHING -> R.string.flashing
|
FlashViewModel.State.FLASHING -> CoreR.string.flashing
|
||||||
FlashViewModel.State.SUCCESS -> R.string.done
|
FlashViewModel.State.SUCCESS -> CoreR.string.done
|
||||||
FlashViewModel.State.FAILED -> R.string.failure
|
FlashViewModel.State.FAILED -> CoreR.string.failure
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (it == FlashViewModel.State.SUCCESS && viewModel.showReboot) {
|
if (it == FlashViewModel.State.SUCCESS && viewModel.showReboot) {
|
||||||
@@ -66,7 +71,7 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>(), MenuProvider {
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
defaultOrientation = activity?.requestedOrientation ?: -1
|
defaultOrientation = activity?.requestedOrientation ?: -1
|
||||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
|
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
viewModel.startFlashing()
|
viewModel.startFlashing()
|
||||||
}
|
}
|
@@ -72,6 +72,7 @@ class FlashViewModel : BaseViewModel() {
|
|||||||
MagiskInstaller.Direct(outItems, logItems).exec()
|
MagiskInstaller.Direct(outItems, logItems).exec()
|
||||||
}
|
}
|
||||||
Const.Value.FLASH_INACTIVE_SLOT -> {
|
Const.Value.FLASH_INACTIVE_SLOT -> {
|
||||||
|
showReboot = false
|
||||||
MagiskInstaller.SecondSlot(outItems, logItems).exec()
|
MagiskInstaller.SecondSlot(outItems, logItems).exec()
|
||||||
}
|
}
|
||||||
Const.Value.PATCH_FILE -> {
|
Const.Value.PATCH_FILE -> {
|
||||||
@@ -104,7 +105,7 @@ class FlashViewModel : BaseViewModel() {
|
|||||||
val name = "magisk_install_log_%s.log".format(
|
val name = "magisk_install_log_%s.log".format(
|
||||||
System.currentTimeMillis().toTime(timeFormatStandard)
|
System.currentTimeMillis().toTime(timeFormatStandard)
|
||||||
)
|
)
|
||||||
val file = MediaStoreUtils.getFile(name, true)
|
val file = MediaStoreUtils.getFile(name)
|
||||||
file.uri.outputStream().bufferedWriter().use { writer ->
|
file.uri.outputStream().bufferedWriter().use { writer ->
|
||||||
synchronized(logItems) {
|
synchronized(logItems) {
|
||||||
logItems.forEach {
|
logItems.forEach {
|
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.ui.home
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.databinding.RvItem
|
import com.topjohnwu.magisk.databinding.RvItem
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
interface Dev {
|
interface Dev {
|
||||||
val name: String
|
val name: String
|
||||||
@@ -24,6 +25,10 @@ private interface RikkaImpl : Dev {
|
|||||||
override val name get() = "RikkaW"
|
override val name get() = "RikkaW"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private interface CanyieImpl : Dev {
|
||||||
|
override val name get() = "canyie"
|
||||||
|
}
|
||||||
|
|
||||||
sealed class DeveloperItem : Dev {
|
sealed class DeveloperItem : Dev {
|
||||||
|
|
||||||
abstract val items: List<IconLink>
|
abstract val items: List<IconLink>
|
||||||
@@ -61,6 +66,14 @@ sealed class DeveloperItem : Dev {
|
|||||||
object : IconLink.Github.User(), RikkaImpl {}
|
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() {
|
sealed class IconLink : RvItem() {
|
||||||
@@ -72,8 +85,8 @@ sealed class IconLink : RvItem() {
|
|||||||
override val layoutRes get() = R.layout.item_icon_link
|
override val layoutRes get() = R.layout.item_icon_link
|
||||||
|
|
||||||
abstract class PayPal : IconLink(), Dev {
|
abstract class PayPal : IconLink(), Dev {
|
||||||
override val icon get() = R.drawable.ic_paypal
|
override val icon get() = CoreR.drawable.ic_paypal
|
||||||
override val title get() = R.string.paypal
|
override val title get() = CoreR.string.paypal
|
||||||
override val link get() = "https://paypal.me/$name"
|
override val link get() = "https://paypal.me/$name"
|
||||||
|
|
||||||
object Project : PayPal() {
|
object Project : PayPal() {
|
||||||
@@ -82,20 +95,20 @@ sealed class IconLink : RvItem() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Patreon : IconLink() {
|
object Patreon : IconLink() {
|
||||||
override val icon get() = R.drawable.ic_patreon
|
override val icon get() = CoreR.drawable.ic_patreon
|
||||||
override val title get() = R.string.patreon
|
override val title get() = CoreR.string.patreon
|
||||||
override val link get() = Const.Url.PATREON_URL
|
override val link get() = Const.Url.PATREON_URL
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Twitter : IconLink(), Dev {
|
abstract class Twitter : IconLink(), Dev {
|
||||||
override val icon get() = R.drawable.ic_twitter
|
override val icon get() = CoreR.drawable.ic_twitter
|
||||||
override val title get() = R.string.twitter
|
override val title get() = CoreR.string.twitter
|
||||||
override val link get() = "https://twitter.com/$name"
|
override val link get() = "https://twitter.com/$name"
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Github : IconLink() {
|
abstract class Github : IconLink() {
|
||||||
override val icon get() = R.drawable.ic_github
|
override val icon get() = CoreR.drawable.ic_github
|
||||||
override val title get() = R.string.github
|
override val title get() = CoreR.string.github
|
||||||
|
|
||||||
abstract class User : Github(), Dev {
|
abstract class User : Github(), Dev {
|
||||||
override val link get() = "https://github.com/$name"
|
override val link get() = "https://github.com/$name"
|
||||||
@@ -107,8 +120,8 @@ sealed class IconLink : RvItem() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class Sponsor : IconLink(), Dev {
|
abstract class Sponsor : IconLink(), Dev {
|
||||||
override val icon get() = R.drawable.ic_favorite
|
override val icon get() = CoreR.drawable.ic_favorite
|
||||||
override val title get() = R.string.github
|
override val title get() = CoreR.string.github
|
||||||
override val link get() = "https://github.com/sponsors/$name"
|
override val link get() = "https://github.com/sponsors/$name"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -14,8 +14,11 @@ import com.topjohnwu.magisk.R
|
|||||||
import com.topjohnwu.magisk.arch.BaseFragment
|
import com.topjohnwu.magisk.arch.BaseFragment
|
||||||
import com.topjohnwu.magisk.arch.viewModel
|
import com.topjohnwu.magisk.arch.viewModel
|
||||||
import com.topjohnwu.magisk.core.Info
|
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.databinding.FragmentHomeMd2Binding
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
import androidx.navigation.findNavController
|
||||||
|
import com.topjohnwu.magisk.arch.NavigationActivity
|
||||||
|
|
||||||
class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider {
|
class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider {
|
||||||
|
|
||||||
@@ -24,8 +27,8 @@ class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.setTitle(R.string.section_home)
|
activity?.setTitle(CoreR.string.section_home)
|
||||||
DownloadService.observeProgress(this, viewModel::onProgressUpdate)
|
DownloadEngine.observeProgress(this, viewModel::onProgressUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkTitle(text: TextView, icon: ImageView) {
|
private fun checkTitle(text: TextView, icon: ImageView) {
|
||||||
@@ -67,7 +70,13 @@ class HomeFragment : BaseFragment<FragmentHomeMd2Binding>(), MenuProvider {
|
|||||||
override fun onMenuItemSelected(item: MenuItem): Boolean {
|
override fun onMenuItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_settings ->
|
R.id.action_settings ->
|
||||||
HomeFragmentDirections.actionHomeFragmentToSettingsFragment().navigate()
|
activity?.let {
|
||||||
|
NavigationActivity.navigate(
|
||||||
|
HomeFragmentDirections.actionHomeFragmentToSettingsFragment(),
|
||||||
|
it.findNavController(R.id.main_nav_host),
|
||||||
|
it.contentResolver,
|
||||||
|
)
|
||||||
|
}
|
||||||
R.id.action_reboot -> activity?.let { RebootMenu.inflate(it).show() }
|
R.id.action_reboot -> activity?.let { RebootMenu.inflate(it).show() }
|
||||||
else -> return super.onOptionsItemSelected(item)
|
else -> return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
@@ -7,13 +7,13 @@ import android.widget.Toast
|
|||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.BuildConfig
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.ActivityExecutor
|
import com.topjohnwu.magisk.arch.ActivityExecutor
|
||||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.arch.ContextExecutor
|
import com.topjohnwu.magisk.arch.ContextExecutor
|
||||||
import com.topjohnwu.magisk.arch.UIActivity
|
import com.topjohnwu.magisk.arch.UIActivity
|
||||||
import com.topjohnwu.magisk.arch.ViewEvent
|
import com.topjohnwu.magisk.arch.ViewEvent
|
||||||
|
import com.topjohnwu.magisk.core.BuildConfig
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.download.Subject
|
import com.topjohnwu.magisk.core.download.Subject
|
||||||
@@ -30,6 +30,7 @@ import com.topjohnwu.magisk.events.SnackbarEvent
|
|||||||
import com.topjohnwu.magisk.utils.asText
|
import com.topjohnwu.magisk.utils.asText
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class HomeViewModel(
|
class HomeViewModel(
|
||||||
private val svc: NetworkService
|
private val svc: NetworkService
|
||||||
@@ -52,7 +53,7 @@ class HomeViewModel(
|
|||||||
get() = when {
|
get() = when {
|
||||||
Info.isRooted && Info.env.isUnsupported -> State.OUTDATED
|
Info.isRooted && Info.env.isUnsupported -> State.OUTDATED
|
||||||
!Info.env.isActive -> State.INVALID
|
!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
|
else -> State.UP_TO_DATE
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,15 +66,15 @@ class HomeViewModel(
|
|||||||
if (isActive)
|
if (isActive)
|
||||||
("$versionString ($versionCode)" + if (isDebug) " (D)" else "").asText()
|
("$versionString ($versionCode)" + if (isDebug) " (D)" else "").asText()
|
||||||
else
|
else
|
||||||
R.string.not_available.asText()
|
CoreR.string.not_available.asText()
|
||||||
}
|
}
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var managerRemoteVersion = R.string.loading.asText()
|
var managerRemoteVersion = CoreR.string.loading.asText()
|
||||||
set(value) = set(value, field, { field = it }, BR.managerRemoteVersion)
|
set(value) = set(value, field, { field = it }, BR.managerRemoteVersion)
|
||||||
|
|
||||||
val managerInstalledVersion
|
val managerInstalledVersion
|
||||||
get() = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" +
|
get() = "${BuildConfig.APP_VERSION_NAME} (${BuildConfig.APP_VERSION_CODE})" +
|
||||||
if (BuildConfig.DEBUG) " (D)" else ""
|
if (BuildConfig.DEBUG) " (D)" else ""
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
@@ -90,19 +91,18 @@ class HomeViewModel(
|
|||||||
|
|
||||||
override suspend fun doLoadWork() {
|
override suspend fun doLoadWork() {
|
||||||
appState = State.LOADING
|
appState = State.LOADING
|
||||||
Info.getRemote(svc)?.apply {
|
Info.fetchUpdate(svc)?.apply {
|
||||||
appState = when {
|
appState = when {
|
||||||
BuildConfig.VERSION_CODE < magisk.versionCode -> State.OUTDATED
|
BuildConfig.APP_VERSION_CODE < versionCode -> State.OUTDATED
|
||||||
else -> State.UP_TO_DATE
|
else -> State.UP_TO_DATE
|
||||||
}
|
}
|
||||||
|
|
||||||
val isDebug = Config.updateChannel == Config.Value.DEBUG_CHANNEL
|
val isDebug = Config.updateChannel == Config.Value.DEBUG_CHANNEL
|
||||||
managerRemoteVersion =
|
managerRemoteVersion =
|
||||||
("${magisk.version} (${magisk.versionCode})" +
|
("$version (${versionCode})" + if (isDebug) " (D)" else "").asText()
|
||||||
if (isDebug) " (D)" else "").asText()
|
|
||||||
} ?: run {
|
} ?: run {
|
||||||
appState = State.INVALID
|
appState = State.INVALID
|
||||||
managerRemoteVersion = R.string.not_available.asText()
|
managerRemoteVersion = CoreR.string.not_available.asText()
|
||||||
}
|
}
|
||||||
ensureEnv()
|
ensureEnv()
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ class HomeViewModel(
|
|||||||
try {
|
try {
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (e: ActivityNotFoundException) {
|
||||||
context.toast(R.string.open_link_failed_toast, Toast.LENGTH_SHORT)
|
context.toast(CoreR.string.open_link_failed_toast, Toast.LENGTH_SHORT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.publish()
|
}.publish()
|
||||||
@@ -129,8 +129,8 @@ class HomeViewModel(
|
|||||||
fun onDeletePressed() = UninstallDialog().show()
|
fun onDeletePressed() = UninstallDialog().show()
|
||||||
|
|
||||||
fun onManagerPressed() = when (appState) {
|
fun onManagerPressed() = when (appState) {
|
||||||
State.LOADING -> SnackbarEvent(R.string.loading).publish()
|
State.LOADING -> SnackbarEvent(CoreR.string.loading).publish()
|
||||||
State.INVALID -> SnackbarEvent(R.string.no_connection).publish()
|
State.INVALID -> SnackbarEvent(CoreR.string.no_connection).publish()
|
||||||
else -> withExternalRW {
|
else -> withExternalRW {
|
||||||
withInstallPermission {
|
withInstallPermission {
|
||||||
ManagerInstallDialog().show()
|
ManagerInstallDialog().show()
|
@@ -1,5 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.ui.home
|
package com.topjohnwu.magisk.ui.home
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.view.ContextThemeWrapper
|
import android.view.ContextThemeWrapper
|
||||||
@@ -7,7 +8,8 @@ import android.view.MenuItem
|
|||||||
import android.widget.PopupMenu
|
import android.widget.PopupMenu
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
import com.topjohnwu.magisk.core.Config
|
||||||
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.core.ktx.reboot as systemReboot
|
import com.topjohnwu.magisk.core.ktx.reboot as systemReboot
|
||||||
|
|
||||||
object RebootMenu {
|
object RebootMenu {
|
||||||
@@ -20,19 +22,30 @@ object RebootMenu {
|
|||||||
R.id.action_reboot_download -> systemReboot("download")
|
R.id.action_reboot_download -> systemReboot("download")
|
||||||
R.id.action_reboot_edl -> systemReboot("edl")
|
R.id.action_reboot_edl -> systemReboot("edl")
|
||||||
R.id.action_reboot_recovery -> systemReboot("recovery")
|
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
|
else -> Unit
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun inflate(activity: BaseActivity): PopupMenu {
|
fun inflate(activity: Activity): PopupMenu {
|
||||||
val themeWrapper = ContextThemeWrapper(activity, R.style.Foundation_PopupMenu)
|
val themeWrapper = ContextThemeWrapper(activity, R.style.Foundation_PopupMenu)
|
||||||
val menu = PopupMenu(themeWrapper, activity.findViewById(R.id.action_reboot))
|
val menu = PopupMenu(themeWrapper, activity.findViewById(R.id.action_reboot))
|
||||||
activity.menuInflater.inflate(R.menu.menu_reboot, menu.menu)
|
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)
|
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.atLeast_28_0()) {
|
||||||
|
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
|
return menu
|
||||||
}
|
}
|
||||||
|
|
@@ -4,6 +4,7 @@ import com.topjohnwu.magisk.R
|
|||||||
import com.topjohnwu.magisk.arch.BaseFragment
|
import com.topjohnwu.magisk.arch.BaseFragment
|
||||||
import com.topjohnwu.magisk.arch.viewModel
|
import com.topjohnwu.magisk.arch.viewModel
|
||||||
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
|
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class InstallFragment : BaseFragment<FragmentInstallMd2Binding>() {
|
class InstallFragment : BaseFragment<FragmentInstallMd2Binding>() {
|
||||||
|
|
||||||
@@ -12,6 +13,6 @@ class InstallFragment : BaseFragment<FragmentInstallMd2Binding>() {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
requireActivity().setTitle(R.string.install)
|
requireActivity().setTitle(CoreR.string.install)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -11,14 +11,13 @@ import androidx.lifecycle.LiveData
|
|||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.BuildConfig
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||||
|
import com.topjohnwu.magisk.core.AppContext
|
||||||
|
import com.topjohnwu.magisk.core.BuildConfig.APP_VERSION_CODE
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Const
|
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
|
||||||
import com.topjohnwu.magisk.core.ktx.toast
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
import com.topjohnwu.magisk.core.repository.NetworkService
|
import com.topjohnwu.magisk.core.repository.NetworkService
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
@@ -33,12 +32,12 @@ import kotlinx.parcelize.Parcelize
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel() {
|
class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel() {
|
||||||
|
|
||||||
val isRooted get() = Info.isRooted
|
val isRooted get() = Info.isRooted
|
||||||
val hideVbmeta = Info.vbmeta || Info.isSamsung || Info.isAB
|
val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && Info.ramdisk)
|
||||||
val skipOptions = Info.isEmulator || (Info.isSAR && !Info.isFDE && hideVbmeta && Info.ramdisk)
|
|
||||||
val noSecondSlot = !isRooted || !Info.isAB || Info.isEmulator
|
val noSecondSlot = !isRooted || !Info.isAB || Info.isEmulator
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
@@ -70,17 +69,16 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
|
|||||||
init {
|
init {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val file = File(AppContext.cacheDir, "${BuildConfig.VERSION_CODE}.md")
|
val noteFile = File(AppContext.cacheDir, "${APP_VERSION_CODE}.md")
|
||||||
val text = when {
|
val noteText = when {
|
||||||
file.exists() -> file.readText()
|
noteFile.exists() -> noteFile.readText()
|
||||||
Const.Url.CHANGELOG_URL.isEmpty() -> ""
|
|
||||||
else -> {
|
else -> {
|
||||||
val str = svc.fetchString(Const.Url.CHANGELOG_URL)
|
val note = svc.fetchUpdate(APP_VERSION_CODE).note
|
||||||
file.writeText(str)
|
noteFile.writeText(note)
|
||||||
str
|
note
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val spanned = markwon.toMarkdown(text)
|
val spanned = markwon.toMarkdown(noteText)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
notes = spanned
|
notes = spanned
|
||||||
}
|
}
|
||||||
@@ -100,14 +98,15 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveState(state: Bundle) {
|
override fun onSaveState(state: Bundle) {
|
||||||
state.putParcelable(INSTALL_STATE_KEY, InstallState(
|
state.putParcelable(
|
||||||
methodId,
|
INSTALL_STATE_KEY, InstallState(
|
||||||
step,
|
methodId,
|
||||||
Config.keepVerity,
|
step,
|
||||||
Config.keepEnc,
|
Config.keepVerity,
|
||||||
Config.patchVbmeta,
|
Config.keepEnc,
|
||||||
Config.recovery
|
Config.recovery
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRestoreState(state: Bundle) {
|
override fun onRestoreState(state: Bundle) {
|
||||||
@@ -116,7 +115,6 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
|
|||||||
step = it.step
|
step = it.step
|
||||||
Config.keepVerity = it.keepVerity
|
Config.keepVerity = it.keepVerity
|
||||||
Config.keepEnc = it.keepEnc
|
Config.keepEnc = it.keepEnc
|
||||||
Config.patchVbmeta = it.patchVbmeta
|
|
||||||
Config.recovery = it.recovery
|
Config.recovery = it.recovery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,8 +122,9 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
|
|||||||
@Parcelize
|
@Parcelize
|
||||||
class UriCallback : ContentResultCallback {
|
class UriCallback : ContentResultCallback {
|
||||||
override fun onActivityLaunch() {
|
override fun onActivityLaunch() {
|
||||||
AppContext.toast(R.string.patch_file_msg, Toast.LENGTH_LONG)
|
AppContext.toast(CoreR.string.patch_file_msg, Toast.LENGTH_LONG)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(result: Uri) {
|
override fun onActivityResult(result: Uri) {
|
||||||
uri.value = result
|
uri.value = result
|
||||||
}
|
}
|
||||||
@@ -137,7 +136,6 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel()
|
|||||||
val step: Int,
|
val step: Int,
|
||||||
val keepVerity: Boolean,
|
val keepVerity: Boolean,
|
||||||
val keepEnc: Boolean,
|
val keepEnc: Boolean,
|
||||||
val patchVbmeta: Boolean,
|
|
||||||
val recovery: Boolean,
|
val recovery: Boolean,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
@@ -5,6 +5,7 @@ import android.view.Menu
|
|||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.HorizontalScrollView
|
||||||
import androidx.core.view.MenuProvider
|
import androidx.core.view.MenuProvider
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
@@ -12,10 +13,12 @@ import com.topjohnwu.magisk.arch.BaseFragment
|
|||||||
import com.topjohnwu.magisk.arch.viewModel
|
import com.topjohnwu.magisk.arch.viewModel
|
||||||
import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding
|
import com.topjohnwu.magisk.databinding.FragmentLogMd2Binding
|
||||||
import com.topjohnwu.magisk.ui.MainActivity
|
import com.topjohnwu.magisk.ui.MainActivity
|
||||||
|
import com.topjohnwu.magisk.utils.AccessibilityUtils
|
||||||
import com.topjohnwu.magisk.utils.MotionRevealHelper
|
import com.topjohnwu.magisk.utils.MotionRevealHelper
|
||||||
import rikka.recyclerview.addEdgeSpacing
|
import rikka.recyclerview.addEdgeSpacing
|
||||||
import rikka.recyclerview.addItemSpacing
|
import rikka.recyclerview.addItemSpacing
|
||||||
import rikka.recyclerview.fixEdgeEffect
|
import rikka.recyclerview.fixEdgeEffect
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class LogFragment : BaseFragment<FragmentLogMd2Binding>(), MenuProvider {
|
class LogFragment : BaseFragment<FragmentLogMd2Binding>(), MenuProvider {
|
||||||
|
|
||||||
@@ -41,7 +44,7 @@ class LogFragment : BaseFragment<FragmentLogMd2Binding>(), MenuProvider {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.setTitle(R.string.logs)
|
activity?.setTitle(CoreR.string.logs)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
@@ -55,6 +58,11 @@ class LogFragment : BaseFragment<FragmentLogMd2Binding>(), MenuProvider {
|
|||||||
addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1)
|
addItemSpacing(R.dimen.l1, R.dimen.l_50, R.dimen.l1)
|
||||||
fixEdgeEffect()
|
fixEdgeEffect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!AccessibilityUtils.isAnimationEnabled(requireContext().contentResolver)) {
|
||||||
|
val scrollView = view.findViewById<HorizontalScrollView>(R.id.log_scroll_magisk)
|
||||||
|
scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@@ -4,10 +4,10 @@ import android.system.Os
|
|||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
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.arch.AsyncLoadViewModel
|
||||||
|
import com.topjohnwu.magisk.core.BuildConfig
|
||||||
import com.topjohnwu.magisk.core.Info
|
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.timeFormatStandard
|
||||||
import com.topjohnwu.magisk.core.ktx.toTime
|
import com.topjohnwu.magisk.core.ktx.toTime
|
||||||
import com.topjohnwu.magisk.core.repository.LogRepository
|
import com.topjohnwu.magisk.core.repository.LogRepository
|
||||||
@@ -69,7 +69,7 @@ class LogViewModel(
|
|||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val filename = "magisk_log_%s.log".format(
|
val filename = "magisk_log_%s.log".format(
|
||||||
System.currentTimeMillis().toTime(timeFormatStandard))
|
System.currentTimeMillis().toTime(timeFormatStandard))
|
||||||
val logFile = MediaStoreUtils.getFile(filename, true)
|
val logFile = MediaStoreUtils.getFile(filename)
|
||||||
logFile.uri.outputStream().bufferedWriter().use { file ->
|
logFile.uri.outputStream().bufferedWriter().use { file ->
|
||||||
file.write("---Detected Device Info---\n\n")
|
file.write("---Detected Device Info---\n\n")
|
||||||
file.write("isAB=${Info.isAB}\n")
|
file.write("isAB=${Info.isAB}\n")
|
||||||
@@ -93,7 +93,7 @@ class LogViewModel(
|
|||||||
if (Info.env.isActive) file.write(magiskLogRaw)
|
if (Info.env.isActive) file.write(magiskLogRaw)
|
||||||
|
|
||||||
file.write("\n---Manager Logs---\n")
|
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()
|
ProcessBuilder("logcat", "-d").start()
|
||||||
.inputStream.reader().use { it.copyTo(file) }
|
.inputStream.reader().use { it.copyTo(file) }
|
||||||
}
|
}
|
@@ -3,13 +3,14 @@ package com.topjohnwu.magisk.ui.log
|
|||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
import com.topjohnwu.magisk.core.AppContext
|
||||||
import com.topjohnwu.magisk.core.ktx.timeDateFormat
|
import com.topjohnwu.magisk.core.ktx.timeDateFormat
|
||||||
import com.topjohnwu.magisk.core.ktx.toTime
|
import com.topjohnwu.magisk.core.ktx.toTime
|
||||||
import com.topjohnwu.magisk.core.model.su.SuLog
|
import com.topjohnwu.magisk.core.model.su.SuLog
|
||||||
import com.topjohnwu.magisk.databinding.DiffItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class SuLogRvItem(val log: SuLog) : ObservableRvItem(), DiffItem<SuLogRvItem> {
|
class SuLogRvItem(val log: SuLog) : ObservableRvItem(), DiffItem<SuLogRvItem> {
|
||||||
|
|
||||||
@@ -31,20 +32,20 @@ class SuLogRvItem(val log: SuLog) : ObservableRvItem(), DiffItem<SuLogRvItem> {
|
|||||||
val res = AppContext.resources
|
val res = AppContext.resources
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
val date = log.time.toTime(timeDateFormat)
|
val date = log.time.toTime(timeDateFormat)
|
||||||
val toUid = res.getString(R.string.target_uid, log.toUid)
|
val toUid = res.getString(CoreR.string.target_uid, log.toUid)
|
||||||
val fromPid = res.getString(R.string.pid, log.fromPid)
|
val fromPid = res.getString(CoreR.string.pid, log.fromPid)
|
||||||
sb.append("$date\n$toUid $fromPid")
|
sb.append("$date\n$toUid $fromPid")
|
||||||
if (log.target != -1) {
|
if (log.target != -1) {
|
||||||
val pid = if (log.target == 0) "magiskd" else log.target.toString()
|
val pid = if (log.target == 0) "magiskd" else log.target.toString()
|
||||||
val target = res.getString(R.string.target_pid, pid)
|
val target = res.getString(CoreR.string.target_pid, pid)
|
||||||
sb.append(" $target")
|
sb.append(" $target")
|
||||||
}
|
}
|
||||||
if (log.context.isNotEmpty()) {
|
if (log.context.isNotEmpty()) {
|
||||||
val context = res.getString(R.string.selinux_context, log.context)
|
val context = res.getString(CoreR.string.selinux_context, log.context)
|
||||||
sb.append("\n$context")
|
sb.append("\n$context")
|
||||||
}
|
}
|
||||||
if (log.gids.isNotEmpty()) {
|
if (log.gids.isNotEmpty()) {
|
||||||
val gids = res.getString(R.string.supp_group, log.gids)
|
val gids = res.getString(CoreR.string.supp_group, log.gids)
|
||||||
sb.append("\n$gids")
|
sb.append("\n$gids")
|
||||||
}
|
}
|
||||||
sb.append("\n${log.command}")
|
sb.append("\n${log.command}")
|
@@ -0,0 +1,108 @@
|
|||||||
|
package com.topjohnwu.magisk.ui.module
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.pm.ActivityInfo
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewTreeObserver
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.arch.BaseFragment
|
||||||
|
import com.topjohnwu.magisk.arch.viewModel
|
||||||
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
|
import com.topjohnwu.magisk.databinding.FragmentActionMd2Binding
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
|
class ActionFragment : BaseFragment<FragmentActionMd2Binding>(), MenuProvider {
|
||||||
|
|
||||||
|
override val layoutRes = R.layout.fragment_action_md2
|
||||||
|
override val viewModel by viewModel<ActionViewModel>()
|
||||||
|
override val snackbarView: View get() = binding.snackbarContainer
|
||||||
|
|
||||||
|
private var defaultOrientation = -1
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
viewModel.args = ActionFragmentArgs.fromBundle(requireArguments())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
activity?.setTitle(viewModel.args.name)
|
||||||
|
binding.closeBtn.setOnClickListener {
|
||||||
|
activity?.onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.state.observe(this) {
|
||||||
|
if (it != ActionViewModel.State.RUNNING) {
|
||||||
|
binding.closeBtn.apply {
|
||||||
|
if (!this.isVisible) this.show()
|
||||||
|
if (!this.isFocused) this.requestFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (it != ActionViewModel.State.SUCCESS) return@observe
|
||||||
|
view?.viewTreeObserver?.addOnWindowFocusChangeListener(
|
||||||
|
object : ViewTreeObserver.OnWindowFocusChangeListener {
|
||||||
|
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||||
|
if (hasFocus) return
|
||||||
|
view?.viewTreeObserver?.removeOnWindowFocusChangeListener(this)
|
||||||
|
view?.context?.apply {
|
||||||
|
toast(
|
||||||
|
getString(CoreR.string.done_action, viewModel.args.name),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
)
|
||||||
|
}
|
||||||
|
viewModel.back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
inflater.inflate(R.menu.menu_flash, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(item: MenuItem): Boolean {
|
||||||
|
return viewModel.onMenuItemClicked(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
defaultOrientation = activity?.requestedOrientation ?: -1
|
||||||
|
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
viewModel.startRunAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("WrongConstant")
|
||||||
|
override fun onDestroyView() {
|
||||||
|
if (defaultOrientation != -1) {
|
||||||
|
activity?.requestedOrientation = defaultOrientation
|
||||||
|
}
|
||||||
|
super.onDestroyView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onKeyEvent(event: KeyEvent): Boolean {
|
||||||
|
return when (event.keyCode) {
|
||||||
|
KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> true
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed(): Boolean {
|
||||||
|
if (viewModel.state.value == ActionViewModel.State.RUNNING) return true
|
||||||
|
return super.onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPreBind(binding: FragmentActionMd2Binding) = Unit
|
||||||
|
}
|
@@ -0,0 +1,88 @@
|
|||||||
|
package com.topjohnwu.magisk.ui.module
|
||||||
|
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.databinding.ObservableArrayList
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||||
|
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.utils.MediaStoreUtils
|
||||||
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
|
||||||
|
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||||
|
import com.topjohnwu.magisk.ui.flash.ConsoleItem
|
||||||
|
import com.topjohnwu.superuser.CallbackList
|
||||||
|
import com.topjohnwu.superuser.Shell
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class ActionViewModel : BaseViewModel() {
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
RUNNING, SUCCESS, FAILED
|
||||||
|
}
|
||||||
|
|
||||||
|
private val _state = MutableLiveData(State.RUNNING)
|
||||||
|
val state: LiveData<State> get() = _state
|
||||||
|
|
||||||
|
val items = ObservableArrayList<ConsoleItem>()
|
||||||
|
lateinit var args: ActionFragmentArgs
|
||||||
|
|
||||||
|
private val logItems = mutableListOf<String>().synchronized()
|
||||||
|
private val outItems = object : CallbackList<String>() {
|
||||||
|
override fun onAddElement(e: String?) {
|
||||||
|
e ?: return
|
||||||
|
items.add(ConsoleItem(e))
|
||||||
|
logItems.add(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startRunAction() = viewModelScope.launch {
|
||||||
|
onResult(withContext(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
Shell.cmd("run_action \'${args.id}\'")
|
||||||
|
.to(outItems, logItems)
|
||||||
|
.exec().isSuccess
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Timber.e(e)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onResult(success: Boolean) {
|
||||||
|
_state.value = if (success) State.SUCCESS else State.FAILED
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onMenuItemClicked(item: MenuItem): Boolean {
|
||||||
|
when (item.itemId) {
|
||||||
|
R.id.action_save -> savePressed()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun savePressed() = withExternalRW {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val name = "%s_action_log_%s.log".format(
|
||||||
|
args.name,
|
||||||
|
System.currentTimeMillis().toTime(timeFormatStandard)
|
||||||
|
)
|
||||||
|
val file = MediaStoreUtils.getFile(name)
|
||||||
|
file.uri.outputStream().bufferedWriter().use { writer ->
|
||||||
|
synchronized(logItems) {
|
||||||
|
logItems.forEach {
|
||||||
|
writer.write(it)
|
||||||
|
writer.newLine()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SnackbarEvent(file.toString()).publish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -11,6 +11,7 @@ import rikka.recyclerview.addEdgeSpacing
|
|||||||
import rikka.recyclerview.addInvalidateItemDecorationsObserver
|
import rikka.recyclerview.addInvalidateItemDecorationsObserver
|
||||||
import rikka.recyclerview.addItemSpacing
|
import rikka.recyclerview.addItemSpacing
|
||||||
import rikka.recyclerview.fixEdgeEffect
|
import rikka.recyclerview.fixEdgeEffect
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class ModuleFragment : BaseFragment<FragmentModuleMd2Binding>() {
|
class ModuleFragment : BaseFragment<FragmentModuleMd2Binding>() {
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ class ModuleFragment : BaseFragment<FragmentModuleMd2Binding>() {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.title = resources.getString(R.string.modules)
|
activity?.title = resources.getString(CoreR.string.modules)
|
||||||
viewModel.data.observe(this) {
|
viewModel.data.observe(this) {
|
||||||
it ?: return@observe
|
it ?: return@observe
|
||||||
val displayName = runCatching { it.displayName }.getOrNull() ?: return@observe
|
val displayName = runCatching { it.displayName }.getOrNull() ?: return@observe
|
@@ -12,6 +12,7 @@ import com.topjohnwu.magisk.databinding.RvItem
|
|||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
import com.topjohnwu.magisk.utils.TextHolder
|
import com.topjohnwu.magisk.utils.TextHolder
|
||||||
import com.topjohnwu.magisk.utils.asText
|
import com.topjohnwu.magisk.utils.asText
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
object InstallModule : RvItem(), DiffItem<InstallModule> {
|
object InstallModule : RvItem(), DiffItem<InstallModule> {
|
||||||
override val layoutRes = R.layout.item_module_download
|
override val layoutRes = R.layout.item_module_download
|
||||||
@@ -24,6 +25,7 @@ class LocalModuleRvItem(
|
|||||||
override val layoutRes = R.layout.item_module_md2
|
override val layoutRes = R.layout.item_module_md2
|
||||||
|
|
||||||
val showNotice: Boolean
|
val showNotice: Boolean
|
||||||
|
val showAction: Boolean
|
||||||
val noticeText: TextHolder
|
val noticeText: TextHolder
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -34,11 +36,12 @@ class LocalModuleRvItem(
|
|||||||
showNotice = zygiskUnloaded ||
|
showNotice = zygiskUnloaded ||
|
||||||
(Info.isZygiskEnabled && isRiru) ||
|
(Info.isZygiskEnabled && isRiru) ||
|
||||||
(!Info.isZygiskEnabled && isZygisk)
|
(!Info.isZygiskEnabled && isZygisk)
|
||||||
|
showAction = item.hasAction && !showNotice
|
||||||
noticeText =
|
noticeText =
|
||||||
when {
|
when {
|
||||||
zygiskUnloaded -> R.string.zygisk_module_unloaded.asText()
|
zygiskUnloaded -> CoreR.string.zygisk_module_unloaded.asText()
|
||||||
isRiru -> R.string.suspend_text_riru.asText(R.string.zygisk.asText())
|
isRiru -> CoreR.string.suspend_text_riru.asText(CoreR.string.zygisk.asText())
|
||||||
else -> R.string.suspend_text_zygisk.asText(R.string.zygisk.asText())
|
else -> CoreR.string.suspend_text_zygisk.asText(CoreR.string.zygisk.asText())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@@ -4,8 +4,10 @@ import android.net.Uri
|
|||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
|
import com.topjohnwu.magisk.MainDirections
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
||||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
import com.topjohnwu.magisk.core.model.module.LocalModule
|
||||||
@@ -22,6 +24,7 @@ import com.topjohnwu.magisk.events.SnackbarEvent
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class ModuleViewModel : AsyncLoadViewModel() {
|
class ModuleViewModel : AsyncLoadViewModel() {
|
||||||
|
|
||||||
@@ -77,7 +80,7 @@ class ModuleViewModel : AsyncLoadViewModel() {
|
|||||||
if (item != null && Info.isConnected.value == true) {
|
if (item != null && Info.isConnected.value == true) {
|
||||||
withExternalRW { OnlineModuleInstallDialog(item).show() }
|
withExternalRW { OnlineModuleInstallDialog(item).show() }
|
||||||
} else {
|
} else {
|
||||||
SnackbarEvent(R.string.no_connection).publish()
|
SnackbarEvent(CoreR.string.no_connection).publish()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun installPressed() = withExternalRW {
|
fun installPressed() = withExternalRW {
|
||||||
@@ -95,6 +98,10 @@ class ModuleViewModel : AsyncLoadViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun runAction(id: String, name: String) {
|
||||||
|
MainDirections.actionActionFragment(id, name).navigate()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val uri = MutableLiveData<Uri?>()
|
private val uri = MutableLiveData<Uri?>()
|
||||||
}
|
}
|
@@ -14,29 +14,34 @@ import com.topjohnwu.magisk.view.MagiskDialog
|
|||||||
|
|
||||||
sealed class BaseSettingsItem : ObservableRvItem() {
|
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
|
override val layoutRes get() = R.layout.item_settings
|
||||||
|
|
||||||
open val icon: Int get() = 0
|
open val icon: Int get() = 0
|
||||||
open val title: TextHolder get() = TextHolder.EMPTY
|
open val title: TextHolder get() = TextHolder.EMPTY
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
open val description: TextHolder get() = TextHolder.EMPTY
|
open val description: TextHolder get() = TextHolder.EMPTY
|
||||||
open val showSwitch get() = false
|
|
||||||
@get:Bindable
|
|
||||||
open val isChecked get() = false
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var isEnabled = true
|
var isEnabled = true
|
||||||
set(value) = set(value, field, { field = it }, BR.enabled, BR.description)
|
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) {
|
open fun onPressed(view: View, handler: Handler) {
|
||||||
handler.onItemPressed(view, this)
|
handler.onItemPressed(view, this) {
|
||||||
|
handler.onItemAction(view, this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
open fun refresh() {}
|
open fun refresh() {}
|
||||||
|
|
||||||
interface Handler {
|
// Only for toggle
|
||||||
fun onItemPressed(view: View, item: BaseSettingsItem, andThen: () -> Unit = {})
|
open val showSwitch get() = false
|
||||||
fun onItemAction(view: View, item: BaseSettingsItem)
|
@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() {
|
abstract class Value<T> : BaseSettingsItem() {
|
||||||
|
|
||||||
@@ -54,9 +59,6 @@ sealed class BaseSettingsItem : ObservableRvItem() {
|
|||||||
override val showSwitch get() = true
|
override val showSwitch get() = true
|
||||||
override val isChecked get() = value
|
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) {
|
override fun onPressed(view: View, handler: Handler) {
|
||||||
// Make sure the checked state is synced
|
// Make sure the checked state is synced
|
||||||
notifyPropertyChanged(BR.checked)
|
notifyPropertyChanged(BR.checked)
|
||||||
@@ -140,5 +142,4 @@ sealed class BaseSettingsItem : ObservableRvItem() {
|
|||||||
abstract class Section : BaseSettingsItem() {
|
abstract class Section : BaseSettingsItem() {
|
||||||
override val layoutRes = R.layout.item_settings_section
|
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.addEdgeSpacing
|
||||||
import rikka.recyclerview.addItemSpacing
|
import rikka.recyclerview.addItemSpacing
|
||||||
import rikka.recyclerview.fixEdgeEffect
|
import rikka.recyclerview.fixEdgeEffect
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class SettingsFragment : BaseFragment<FragmentSettingsMd2Binding>() {
|
class SettingsFragment : BaseFragment<FragmentSettingsMd2Binding>() {
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsMd2Binding>() {
|
|||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
|
|
||||||
activity?.title = resources.getString(R.string.settings)
|
activity?.title = resources.getString(CoreR.string.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
@@ -7,82 +7,70 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.BuildConfig
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.core.BuildConfig
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
|
||||||
import com.topjohnwu.magisk.core.ktx.activity
|
import com.topjohnwu.magisk.core.ktx.activity
|
||||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
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.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.DialogSettingsAppNameBinding
|
||||||
import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding
|
import com.topjohnwu.magisk.databinding.DialogSettingsDownloadPathBinding
|
||||||
import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
|
import com.topjohnwu.magisk.databinding.DialogSettingsUpdateChannelBinding
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
|
import com.topjohnwu.magisk.utils.TextHolder
|
||||||
import com.topjohnwu.magisk.utils.asText
|
import com.topjohnwu.magisk.utils.asText
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
// --- Customization
|
// --- Customization
|
||||||
|
|
||||||
object Customization : BaseSettingsItem.Section() {
|
object Customization : BaseSettingsItem.Section() {
|
||||||
override val title = R.string.settings_customization.asText()
|
override val title = CoreR.string.settings_customization.asText()
|
||||||
}
|
}
|
||||||
|
|
||||||
object Language : BaseSettingsItem.Selector() {
|
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
|
override var value
|
||||||
get() = index
|
get() = tags.indexOf(Config.locale)
|
||||||
set(value) {
|
set(value) {
|
||||||
index = value
|
Config.locale = tags[value]
|
||||||
Config.locale = entryValues[value]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val title = R.string.language.asText()
|
override val title = CoreR.string.language.asText()
|
||||||
|
|
||||||
private var entries = emptyArray<String>()
|
override fun entries(res: Resources) = names
|
||||||
private var entryValues = emptyArray<String>()
|
override fun descriptions(res: Resources) = names
|
||||||
private var index = -1
|
}
|
||||||
|
|
||||||
override fun entries(res: Resources) = entries
|
object LanguageSystem : BaseSettingsItem.Blank() {
|
||||||
override fun descriptions(res: Resources) = entries
|
override val title = CoreR.string.language.asText()
|
||||||
|
override val description: TextHolder
|
||||||
override fun onPressed(view: View, handler: Handler) {
|
get() {
|
||||||
if (entries.isNotEmpty())
|
val locale = LocaleSetting.instance.appLocale
|
||||||
super.onPressed(view, handler)
|
return locale?.getDisplayName(locale)?.asText() ?: CoreR.string.system_default.asText()
|
||||||
}
|
|
||||||
|
|
||||||
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 Theme : BaseSettingsItem.Blank() {
|
object Theme : BaseSettingsItem.Blank() {
|
||||||
override val icon = R.drawable.ic_paint
|
override val icon = R.drawable.ic_paint
|
||||||
override val title = R.string.section_theme.asText()
|
override val title = CoreR.string.section_theme.asText()
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- App
|
// --- App
|
||||||
|
|
||||||
object AppSettings : BaseSettingsItem.Section() {
|
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() {
|
object Hide : BaseSettingsItem.Input() {
|
||||||
override val title = R.string.settings_hide_app_title.asText()
|
override val title = CoreR.string.settings_hide_app_title.asText()
|
||||||
override val description = R.string.settings_hide_app_summary.asText()
|
override val description = CoreR.string.settings_hide_app_summary.asText()
|
||||||
override var value = ""
|
override var value = ""
|
||||||
|
|
||||||
override val inputResult
|
override val inputResult
|
||||||
@@ -93,7 +81,7 @@ object Hide : BaseSettingsItem.Input() {
|
|||||||
set(value) = set(value, field, { field = it }, BR.result, BR.error)
|
set(value) = set(value, field, { field = it }, BR.result, BR.error)
|
||||||
|
|
||||||
val maxLength
|
val maxLength
|
||||||
get() = HideAPK.MAX_LABEL_LENGTH
|
get() = AppMigration.MAX_LABEL_LENGTH
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
val isError
|
val isError
|
||||||
@@ -104,14 +92,14 @@ object Hide : BaseSettingsItem.Input() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Restore : BaseSettingsItem.Blank() {
|
object Restore : BaseSettingsItem.Blank() {
|
||||||
override val title = R.string.settings_restore_app_title.asText()
|
override val title = CoreR.string.settings_restore_app_title.asText()
|
||||||
override val description = R.string.settings_restore_app_summary.asText()
|
override val description = CoreR.string.settings_restore_app_summary.asText()
|
||||||
|
|
||||||
override fun onPressed(view: View, handler: Handler) {
|
override fun onPressed(view: View, handler: Handler) {
|
||||||
handler.onItemPressed(view, this) {
|
handler.onItemPressed(view, this) {
|
||||||
MagiskDialog(view.activity).apply {
|
MagiskDialog(view.activity).apply {
|
||||||
setTitle(R.string.settings_restore_app_title)
|
setTitle(CoreR.string.settings_restore_app_title)
|
||||||
setMessage(R.string.restore_app_confirmation)
|
setMessage(CoreR.string.restore_app_confirmation)
|
||||||
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
setButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||||
text = android.R.string.ok
|
text = android.R.string.ok
|
||||||
onClick {
|
onClick {
|
||||||
@@ -129,8 +117,8 @@ object Restore : BaseSettingsItem.Blank() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object AddShortcut : BaseSettingsItem.Blank() {
|
object AddShortcut : BaseSettingsItem.Blank() {
|
||||||
override val title = R.string.add_shortcut_title.asText()
|
override val title = CoreR.string.add_shortcut_title.asText()
|
||||||
override val description = R.string.setting_add_shortcut_summary.asText()
|
override val description = CoreR.string.setting_add_shortcut_summary.asText()
|
||||||
}
|
}
|
||||||
|
|
||||||
object DownloadPath : BaseSettingsItem.Input() {
|
object DownloadPath : BaseSettingsItem.Input() {
|
||||||
@@ -141,7 +129,7 @@ object DownloadPath : BaseSettingsItem.Input() {
|
|||||||
notifyPropertyChanged(BR.description)
|
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 val description get() = MediaStoreUtils.fullPath(value).asText()
|
||||||
|
|
||||||
override var inputResult: String = value
|
override var inputResult: String = value
|
||||||
@@ -159,29 +147,21 @@ object UpdateChannel : BaseSettingsItem.Selector() {
|
|||||||
get() = Config.updateChannel
|
get() = Config.updateChannel
|
||||||
set(value) {
|
set(value) {
|
||||||
Config.updateChannel = value
|
Config.updateChannel = value
|
||||||
Info.remote = Info.EMPTY_REMOTE
|
Info.resetUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val title = R.string.settings_update_channel_title.asText()
|
override val title = CoreR.string.settings_update_channel_title.asText()
|
||||||
|
override val entryRes = CoreR.array.update_channel
|
||||||
override val entryRes = R.array.update_channel
|
|
||||||
override fun entries(res: Resources): Array<String> {
|
|
||||||
return super.entries(res).let {
|
|
||||||
if (!Const.APP_IS_CANARY && !BuildConfig.DEBUG)
|
|
||||||
it.copyOfRange(0, Config.Value.CANARY_CHANNEL)
|
|
||||||
else it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object UpdateChannelUrl : BaseSettingsItem.Input() {
|
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 val description get() = value.asText()
|
||||||
override var value
|
override var value
|
||||||
get() = Config.customChannelUrl
|
get() = Config.customChannelUrl
|
||||||
set(value) {
|
set(value) {
|
||||||
Config.customChannelUrl = value
|
Config.customChannelUrl = value
|
||||||
Info.remote = Info.EMPTY_REMOTE
|
Info.resetUpdate()
|
||||||
notifyPropertyChanged(BR.description)
|
notifyPropertyChanged(BR.description)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,56 +177,51 @@ object UpdateChannelUrl : BaseSettingsItem.Input() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object UpdateChecker : BaseSettingsItem.Toggle() {
|
object UpdateChecker : BaseSettingsItem.Toggle() {
|
||||||
override val title = R.string.settings_check_update_title.asText()
|
override val title = CoreR.string.settings_check_update_title.asText()
|
||||||
override val description = R.string.settings_check_update_summary.asText()
|
override val description = CoreR.string.settings_check_update_summary.asText()
|
||||||
override var value by Config::checkUpdate
|
override var value by Config::checkUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
object DoHToggle : BaseSettingsItem.Toggle() {
|
object DoHToggle : BaseSettingsItem.Toggle() {
|
||||||
override val title = R.string.settings_doh_title.asText()
|
override val title = CoreR.string.settings_doh_title.asText()
|
||||||
override val description = R.string.settings_doh_description.asText()
|
override val description = CoreR.string.settings_doh_description.asText()
|
||||||
override var value by Config::doh
|
override var value by Config::doh
|
||||||
}
|
}
|
||||||
|
|
||||||
object SystemlessHosts : BaseSettingsItem.Blank() {
|
object SystemlessHosts : BaseSettingsItem.Blank() {
|
||||||
override val title = R.string.settings_hosts_title.asText()
|
override val title = CoreR.string.settings_hosts_title.asText()
|
||||||
override val description = R.string.settings_hosts_summary.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
|
// --- Magisk
|
||||||
|
|
||||||
object Magisk : BaseSettingsItem.Section() {
|
object Magisk : BaseSettingsItem.Section() {
|
||||||
override val title = R.string.magisk.asText()
|
override val title = CoreR.string.magisk.asText()
|
||||||
}
|
}
|
||||||
|
|
||||||
object Zygisk : BaseSettingsItem.Toggle() {
|
object Zygisk : BaseSettingsItem.Toggle() {
|
||||||
override val title = R.string.zygisk.asText()
|
override val title = CoreR.string.zygisk.asText()
|
||||||
override val description get() =
|
override val description get() =
|
||||||
if (mismatch) R.string.reboot_apply_change.asText()
|
if (mismatch) CoreR.string.reboot_apply_change.asText()
|
||||||
else R.string.settings_zygisk_summary.asText()
|
else CoreR.string.settings_zygisk_summary.asText()
|
||||||
override var value
|
override var value
|
||||||
get() = Config.zygisk
|
get() = Config.zygisk
|
||||||
set(value) {
|
set(value) {
|
||||||
Config.zygisk = value
|
Config.zygisk = value
|
||||||
DenyList.isEnabled = value
|
|
||||||
DenyListConfig.isEnabled = value
|
|
||||||
notifyPropertyChanged(BR.description)
|
notifyPropertyChanged(BR.description)
|
||||||
DenyList.notifyPropertyChanged(BR.description)
|
|
||||||
}
|
}
|
||||||
val mismatch get() = value != Info.isZygiskEnabled
|
val mismatch get() = value != Info.isZygiskEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
object DenyList : BaseSettingsItem.Toggle() {
|
object DenyList : BaseSettingsItem.Toggle() {
|
||||||
override val title = R.string.settings_denylist_title.asText()
|
override val title = CoreR.string.settings_denylist_title.asText()
|
||||||
override val description get() =
|
override val description get() = CoreR.string.settings_denylist_summary.asText()
|
||||||
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 var value = Config.denyList
|
override var value = Config.denyList
|
||||||
set(value) {
|
set(value) {
|
||||||
@@ -261,59 +236,48 @@ object DenyList : BaseSettingsItem.Toggle() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refresh() {
|
|
||||||
isEnabled = Zygisk.value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object DenyListConfig : BaseSettingsItem.Blank() {
|
object DenyListConfig : BaseSettingsItem.Blank() {
|
||||||
override val title = R.string.settings_denylist_config_title.asText()
|
override val title = CoreR.string.settings_denylist_config_title.asText()
|
||||||
override val description = R.string.settings_denylist_config_summary.asText()
|
override val description = CoreR.string.settings_denylist_config_summary.asText()
|
||||||
override fun refresh() {
|
|
||||||
isEnabled = Zygisk.value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Superuser
|
// --- Superuser
|
||||||
|
|
||||||
object Tapjack : BaseSettingsItem.Toggle() {
|
object Tapjack : BaseSettingsItem.Toggle() {
|
||||||
override val title = R.string.settings_su_tapjack_title.asText()
|
override val title = CoreR.string.settings_su_tapjack_title.asText()
|
||||||
override val description = R.string.settings_su_tapjack_summary.asText()
|
override val description = CoreR.string.settings_su_tapjack_summary.asText()
|
||||||
override var value by Config::suTapjack
|
override var value by Config::suTapjack
|
||||||
}
|
}
|
||||||
|
|
||||||
object Biometrics : BaseSettingsItem.Toggle() {
|
object Authentication : BaseSettingsItem.Toggle() {
|
||||||
override val title = R.string.settings_su_biometric_title.asText()
|
override val title = CoreR.string.settings_su_auth_title.asText()
|
||||||
override var description = R.string.settings_su_biometric_summary.asText()
|
override var description = CoreR.string.settings_su_auth_summary.asText()
|
||||||
override var value
|
override var value by Config::suAuth
|
||||||
get() = ServiceLocator.biometrics.isEnabled
|
|
||||||
set(value) {
|
|
||||||
Config.suBiometric = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun refresh() {
|
override fun refresh() {
|
||||||
isEnabled = ServiceLocator.biometrics.isSupported
|
isEnabled = Info.isDeviceSecure
|
||||||
if (!isEnabled) {
|
if (!isEnabled) {
|
||||||
description = R.string.no_biometric.asText()
|
description = CoreR.string.settings_su_auth_insecure.asText()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Superuser : BaseSettingsItem.Section() {
|
object Superuser : BaseSettingsItem.Section() {
|
||||||
override val title = R.string.superuser.asText()
|
override val title = CoreR.string.superuser.asText()
|
||||||
}
|
}
|
||||||
|
|
||||||
object AccessMode : BaseSettingsItem.Selector() {
|
object AccessMode : BaseSettingsItem.Selector() {
|
||||||
override val title = R.string.superuser_access.asText()
|
override val title = CoreR.string.superuser_access.asText()
|
||||||
override val entryRes = R.array.su_access
|
override val entryRes = CoreR.array.su_access
|
||||||
override var value by Config::rootMode
|
override var value by Config::rootMode
|
||||||
}
|
}
|
||||||
|
|
||||||
object MultiuserMode : BaseSettingsItem.Selector() {
|
object MultiuserMode : BaseSettingsItem.Selector() {
|
||||||
override val title = R.string.multiuser_mode.asText()
|
override val title = CoreR.string.multiuser_mode.asText()
|
||||||
override val entryRes = R.array.multiuser_mode
|
override val entryRes = CoreR.array.multiuser_mode
|
||||||
override val descriptionRes = R.array.multiuser_summary
|
override val descriptionRes = CoreR.array.multiuser_summary
|
||||||
override var value by Config::suMultiuserMode
|
override var value by Config::suMultiuserMode
|
||||||
|
|
||||||
override fun refresh() {
|
override fun refresh() {
|
||||||
@@ -322,21 +286,21 @@ object MultiuserMode : BaseSettingsItem.Selector() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object MountNamespaceMode : BaseSettingsItem.Selector() {
|
object MountNamespaceMode : BaseSettingsItem.Selector() {
|
||||||
override val title = R.string.mount_namespace_mode.asText()
|
override val title = CoreR.string.mount_namespace_mode.asText()
|
||||||
override val entryRes = R.array.namespace
|
override val entryRes = CoreR.array.namespace
|
||||||
override val descriptionRes = R.array.namespace_summary
|
override val descriptionRes = CoreR.array.namespace_summary
|
||||||
override var value by Config::suMntNamespaceMode
|
override var value by Config::suMntNamespaceMode
|
||||||
}
|
}
|
||||||
|
|
||||||
object AutomaticResponse : BaseSettingsItem.Selector() {
|
object AutomaticResponse : BaseSettingsItem.Selector() {
|
||||||
override val title = R.string.auto_response.asText()
|
override val title = CoreR.string.auto_response.asText()
|
||||||
override val entryRes = R.array.auto_response
|
override val entryRes = CoreR.array.auto_response
|
||||||
override var value by Config::suAutoResponse
|
override var value by Config::suAutoResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
object RequestTimeout : BaseSettingsItem.Selector() {
|
object RequestTimeout : BaseSettingsItem.Selector() {
|
||||||
override val title = R.string.request_timeout.asText()
|
override val title = CoreR.string.request_timeout.asText()
|
||||||
override val entryRes = R.array.request_timeout
|
override val entryRes = CoreR.array.request_timeout
|
||||||
|
|
||||||
private val entryValues = listOf(10, 15, 20, 30, 45, 60)
|
private val entryValues = listOf(10, 15, 20, 30, 45, 60)
|
||||||
override var value = entryValues.indexOfFirst { it == Config.suDefaultTimeout }
|
override var value = entryValues.indexOfFirst { it == Config.suDefaultTimeout }
|
||||||
@@ -347,17 +311,23 @@ object RequestTimeout : BaseSettingsItem.Selector() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object SUNotification : BaseSettingsItem.Selector() {
|
object SUNotification : BaseSettingsItem.Selector() {
|
||||||
override val title = R.string.superuser_notification.asText()
|
override val title = CoreR.string.superuser_notification.asText()
|
||||||
override val entryRes = R.array.su_notification
|
override val entryRes = CoreR.array.su_notification
|
||||||
override var value by Config::suNotification
|
override var value by Config::suNotification
|
||||||
}
|
}
|
||||||
|
|
||||||
object Reauthenticate : BaseSettingsItem.Toggle() {
|
object Reauthenticate : BaseSettingsItem.Toggle() {
|
||||||
override val title = R.string.settings_su_reauth_title.asText()
|
override val title = CoreR.string.settings_su_reauth_title.asText()
|
||||||
override val description = R.string.settings_su_reauth_summary.asText()
|
override val description = CoreR.string.settings_su_reauth_summary.asText()
|
||||||
override var value by Config::suReAuth
|
override var value by Config::suReAuth
|
||||||
|
|
||||||
override fun refresh() {
|
override fun refresh() {
|
||||||
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Info.showSuperUser
|
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object Restrict : BaseSettingsItem.Toggle() {
|
||||||
|
override val title = CoreR.string.settings_su_restrict_title.asText()
|
||||||
|
override val description = CoreR.string.settings_su_restrict_summary.asText()
|
||||||
|
override var value by Config::suRestrict
|
||||||
|
}
|
@@ -1,26 +1,32 @@
|
|||||||
package com.topjohnwu.magisk.ui.settings
|
package com.topjohnwu.magisk.ui.settings
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.provider.Settings
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
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.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.Const
|
||||||
import com.topjohnwu.magisk.core.Info
|
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.isRunningAsStub
|
||||||
import com.topjohnwu.magisk.core.ktx.activity
|
import com.topjohnwu.magisk.core.ktx.activity
|
||||||
import com.topjohnwu.magisk.core.ktx.toast
|
import com.topjohnwu.magisk.core.ktx.toast
|
||||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
import com.topjohnwu.magisk.core.tasks.AppMigration
|
||||||
|
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
||||||
|
import com.topjohnwu.magisk.core.utils.RootUtils
|
||||||
import com.topjohnwu.magisk.databinding.bindExtra
|
import com.topjohnwu.magisk.databinding.bindExtra
|
||||||
import com.topjohnwu.magisk.events.AddHomeIconEvent
|
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.events.SnackbarEvent
|
||||||
import com.topjohnwu.superuser.Shell
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
||||||
@@ -30,20 +36,14 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
|||||||
it.put(BR.handler, this)
|
it.put(BR.handler, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
|
||||||
viewModelScope.launch {
|
|
||||||
Language.loadLanguages(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createItems(): List<BaseSettingsItem> {
|
private fun createItems(): List<BaseSettingsItem> {
|
||||||
val context = AppContext
|
val context = AppContext
|
||||||
val hidden = context.packageName != BuildConfig.APPLICATION_ID
|
val hidden = context.packageName != BuildConfig.APP_PACKAGE_NAME
|
||||||
|
|
||||||
// Customization
|
// Customization
|
||||||
val list = mutableListOf(
|
val list = mutableListOf(
|
||||||
Customization,
|
Customization,
|
||||||
Theme, Language
|
Theme, if (LocaleSetting.useLocaleManager) LanguageSystem else Language
|
||||||
)
|
)
|
||||||
if (isRunningAsStub && ShortcutManagerCompat.isRequestPinShortcutSupported(context))
|
if (isRunningAsStub && ShortcutManagerCompat.isRequestPinShortcutSupported(context))
|
||||||
list.add(AddShortcut)
|
list.add(AddShortcut)
|
||||||
@@ -51,7 +51,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
|||||||
// Manager
|
// Manager
|
||||||
list.addAll(listOf(
|
list.addAll(listOf(
|
||||||
AppSettings,
|
AppSettings,
|
||||||
UpdateChannel, UpdateChannelUrl, DoHToggle, UpdateChecker, DownloadPath
|
UpdateChannel, UpdateChannelUrl, DoHToggle, UpdateChecker, DownloadPath, RandNameToggle
|
||||||
))
|
))
|
||||||
if (Info.env.isActive && Const.USER_ID == 0) {
|
if (Info.env.isActive && Const.USER_ID == 0) {
|
||||||
if (hidden) list.add(Restore) else list.add(Hide)
|
if (hidden) list.add(Restore) else list.add(Hide)
|
||||||
@@ -72,7 +72,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
|||||||
if (Info.showSuperUser) {
|
if (Info.showSuperUser) {
|
||||||
list.addAll(listOf(
|
list.addAll(listOf(
|
||||||
Superuser,
|
Superuser,
|
||||||
Tapjack, Biometrics, AccessMode, MultiuserMode, MountNamespaceMode,
|
Tapjack, Authentication, AccessMode, MultiuserMode, MountNamespaceMode,
|
||||||
AutomaticResponse, RequestTimeout, SUNotification
|
AutomaticResponse, RequestTimeout, SUNotification
|
||||||
))
|
))
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||||
@@ -83,35 +83,45 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
|||||||
// Can hide overlay windows on 12.0+
|
// Can hide overlay windows on 12.0+
|
||||||
list.remove(Tapjack)
|
list.remove(Tapjack)
|
||||||
}
|
}
|
||||||
|
if (Const.Version.atLeast_30_1()) {
|
||||||
|
list.add(Restrict)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemPressed(view: View, item: BaseSettingsItem, andThen: () -> Unit) {
|
override fun onItemPressed(view: View, item: BaseSettingsItem, doAction: () -> Unit) {
|
||||||
when (item) {
|
when (item) {
|
||||||
DownloadPath -> withExternalRW(andThen)
|
DownloadPath -> withExternalRW(doAction)
|
||||||
UpdateChecker -> withPostNotificationPermission(andThen)
|
UpdateChecker -> withPostNotificationPermission(doAction)
|
||||||
Biometrics -> authenticate(andThen)
|
Authentication -> AuthEvent(doAction).publish()
|
||||||
Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate()
|
AutomaticResponse -> if (Config.suAuth) AuthEvent(doAction).publish() else doAction()
|
||||||
DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate()
|
else -> doAction()
|
||||||
SystemlessHosts -> createHosts()
|
|
||||||
Hide, Restore -> withInstallPermission(andThen)
|
|
||||||
AddShortcut -> AddHomeIconEvent().publish()
|
|
||||||
else -> andThen()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemAction(view: View, item: BaseSettingsItem) {
|
override fun onItemAction(view: View, item: BaseSettingsItem) {
|
||||||
when (item) {
|
when (item) {
|
||||||
|
Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate()
|
||||||
|
LanguageSystem -> launchAppLocaleSettings(view.activity)
|
||||||
|
AddShortcut -> AddHomeIconEvent().publish()
|
||||||
|
SystemlessHosts -> createHosts()
|
||||||
|
DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate()
|
||||||
UpdateChannel -> openUrlIfNecessary(view)
|
UpdateChannel -> openUrlIfNecessary(view)
|
||||||
is Hide -> viewModelScope.launch { HideAPK.hide(view.activity, item.value) }
|
is Hide -> viewModelScope.launch { AppMigration.hide(view.activity, item.value) }
|
||||||
Restore -> viewModelScope.launch { HideAPK.restore(view.activity) }
|
Restore -> viewModelScope.launch { AppMigration.restore(view.activity) }
|
||||||
Zygisk -> if (Zygisk.mismatch) SnackbarEvent(R.string.reboot_apply_change).publish()
|
Zygisk -> if (Zygisk.mismatch) SnackbarEvent(R.string.reboot_apply_change).publish()
|
||||||
else -> Unit
|
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) {
|
private fun openUrlIfNecessary(view: View) {
|
||||||
UpdateChannelUrl.refresh()
|
UpdateChannelUrl.refresh()
|
||||||
if (UpdateChannelUrl.isEnabled && UpdateChannelUrl.value.isBlank()) {
|
if (UpdateChannelUrl.isEnabled && UpdateChannelUrl.value.isBlank()) {
|
||||||
@@ -119,15 +129,9 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun authenticate(callback: () -> Unit) {
|
|
||||||
BiometricEvent {
|
|
||||||
// allow the change on success
|
|
||||||
onSuccess { callback() }
|
|
||||||
}.publish()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createHosts() {
|
private fun createHosts() {
|
||||||
Shell.cmd("add_hosts_module").submit {
|
viewModelScope.launch {
|
||||||
|
RootUtils.addSystemlessHosts()
|
||||||
AppContext.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
|
AppContext.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -4,11 +4,13 @@ import android.graphics.drawable.Drawable
|
|||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||||
import com.topjohnwu.magisk.databinding.DiffItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.ItemWrapper
|
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||||
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||||
import com.topjohnwu.magisk.databinding.set
|
import com.topjohnwu.magisk.databinding.set
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class PolicyRvItem(
|
class PolicyRvItem(
|
||||||
private val viewModel: SuperuserViewModel,
|
private val viewModel: SuperuserViewModel,
|
||||||
@@ -33,14 +35,34 @@ class PolicyRvItem(
|
|||||||
var isExpanded = false
|
var isExpanded = false
|
||||||
set(value) = set(value, field, { field = it }, BR.expanded)
|
set(value) = set(value, field, { field = it }, BR.expanded)
|
||||||
|
|
||||||
|
val showSlider = Config.suRestrict || item.policy == SuPolicy.RESTRICT
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var isEnabled
|
var isEnabled
|
||||||
get() = item.policy == SuPolicy.ALLOW
|
get() = item.policy >= SuPolicy.ALLOW
|
||||||
set(value) = setImpl(value, isEnabled) {
|
set(value) = setImpl(value, isEnabled) {
|
||||||
notifyPropertyChanged(BR.enabled)
|
notifyPropertyChanged(BR.enabled)
|
||||||
viewModel.togglePolicy(this, value)
|
viewModel.updatePolicy(this, if (it) SuPolicy.ALLOW else SuPolicy.DENY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@get:Bindable
|
||||||
|
var sliderValue
|
||||||
|
get() = item.policy
|
||||||
|
set(value) = setImpl(value, sliderValue) {
|
||||||
|
notifyPropertyChanged(BR.sliderValue)
|
||||||
|
notifyPropertyChanged(BR.enabled)
|
||||||
|
viewModel.updatePolicy(this, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val sliderValueToPolicyString: (Float) -> Int = { value ->
|
||||||
|
when (value.toInt()) {
|
||||||
|
1 -> CoreR.string.deny
|
||||||
|
2 -> CoreR.string.restrict
|
||||||
|
3 -> CoreR.string.grant
|
||||||
|
else -> CoreR.string.deny
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var shouldNotify
|
var shouldNotify
|
||||||
get() = item.notification
|
get() = item.notification
|
@@ -9,6 +9,7 @@ import com.topjohnwu.magisk.databinding.FragmentSuperuserMd2Binding
|
|||||||
import rikka.recyclerview.addEdgeSpacing
|
import rikka.recyclerview.addEdgeSpacing
|
||||||
import rikka.recyclerview.addItemSpacing
|
import rikka.recyclerview.addItemSpacing
|
||||||
import rikka.recyclerview.fixEdgeEffect
|
import rikka.recyclerview.fixEdgeEffect
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class SuperuserFragment : BaseFragment<FragmentSuperuserMd2Binding>() {
|
class SuperuserFragment : BaseFragment<FragmentSuperuserMd2Binding>() {
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ class SuperuserFragment : BaseFragment<FragmentSuperuserMd2Binding>() {
|
|||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
activity?.title = resources.getString(R.string.superuser)
|
activity?.title = resources.getString(CoreR.string.superuser)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
@@ -8,24 +8,28 @@ import androidx.databinding.Bindable
|
|||||||
import androidx.databinding.ObservableArrayList
|
import androidx.databinding.ObservableArrayList
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
|
||||||
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
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.Info
|
||||||
|
import com.topjohnwu.magisk.core.R
|
||||||
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
|
||||||
import com.topjohnwu.magisk.core.ktx.getLabel
|
import com.topjohnwu.magisk.core.ktx.getLabel
|
||||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
import com.topjohnwu.magisk.databinding.MergeObservableList
|
||||||
import com.topjohnwu.magisk.databinding.*
|
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.dialog.SuperuserRevokeDialog
|
||||||
import com.topjohnwu.magisk.events.BiometricEvent
|
import com.topjohnwu.magisk.events.AuthEvent
|
||||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||||
import com.topjohnwu.magisk.utils.asText
|
import com.topjohnwu.magisk.utils.asText
|
||||||
import com.topjohnwu.magisk.view.TextItem
|
import com.topjohnwu.magisk.view.TextItem
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class SuperuserViewModel(
|
class SuperuserViewModel(
|
||||||
private val db: PolicyDao
|
private val db: PolicyDao
|
||||||
@@ -74,8 +78,8 @@ class SuperuserViewModel(
|
|||||||
this@SuperuserViewModel, policy,
|
this@SuperuserViewModel, policy,
|
||||||
info.packageName,
|
info.packageName,
|
||||||
info.sharedUserId != null,
|
info.sharedUserId != null,
|
||||||
info.applicationInfo.loadIcon(pm),
|
info.applicationInfo?.loadIcon(pm) ?: pm.defaultActivityIcon,
|
||||||
info.applicationInfo.getLabel(pm)
|
info.applicationInfo?.getLabel(pm) ?: info.packageName
|
||||||
)
|
)
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
null
|
null
|
||||||
@@ -88,7 +92,7 @@ class SuperuserViewModel(
|
|||||||
policies.addAll(map)
|
policies.addAll(map)
|
||||||
}
|
}
|
||||||
policies.sortWith(compareBy(
|
policies.sortWith(compareBy(
|
||||||
{ it.appName.lowercase(currentLocale) },
|
{ it.appName.lowercase(Locale.ROOT) },
|
||||||
{ it.packageName }
|
{ it.packageName }
|
||||||
))
|
))
|
||||||
itemsPolicies.update(policies)
|
itemsPolicies.update(policies)
|
||||||
@@ -113,10 +117,8 @@ class SuperuserViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ServiceLocator.biometrics.isEnabled) {
|
if (Config.suAuth) {
|
||||||
BiometricEvent {
|
AuthEvent { updateState() }.publish()
|
||||||
onSuccess { updateState() }
|
|
||||||
}.publish()
|
|
||||||
} else {
|
} else {
|
||||||
SuperuserRevokeDialog(item.title) { updateState() }.show()
|
SuperuserRevokeDialog(item.title) { updateState() }.show()
|
||||||
}
|
}
|
||||||
@@ -154,24 +156,23 @@ class SuperuserViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun togglePolicy(item: PolicyRvItem, enable: Boolean) {
|
fun updatePolicy(item: PolicyRvItem, policy: Int) {
|
||||||
val items = itemsPolicies.filter { it.item.uid == item.item.uid }
|
val items = itemsPolicies.filter { it.item.uid == item.item.uid }
|
||||||
fun updateState() {
|
fun updateState() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val res = if (enable) R.string.su_snack_grant else R.string.su_snack_deny
|
val res = if (policy >= SuPolicy.ALLOW) R.string.su_snack_grant else R.string.su_snack_deny
|
||||||
item.item.policy = if (enable) SuPolicy.ALLOW else SuPolicy.DENY
|
item.item.policy = policy
|
||||||
db.update(item.item)
|
db.update(item.item)
|
||||||
items.forEach {
|
items.forEach {
|
||||||
it.notifyPropertyChanged(BR.enabled)
|
it.notifyPropertyChanged(BR.enabled)
|
||||||
|
it.notifyPropertyChanged(BR.sliderValue)
|
||||||
}
|
}
|
||||||
SnackbarEvent(res.asText(item.appName)).publish()
|
SnackbarEvent(res.asText(item.appName)).publish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ServiceLocator.biometrics.isEnabled) {
|
if (Config.suAuth) {
|
||||||
BiometricEvent {
|
AuthEvent { updateState() }.publish()
|
||||||
onSuccess { updateState() }
|
|
||||||
}.publish()
|
|
||||||
} else {
|
} else {
|
||||||
updateState()
|
updateState()
|
||||||
}
|
}
|
@@ -11,6 +11,7 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.UIActivity
|
import com.topjohnwu.magisk.arch.UIActivity
|
||||||
import com.topjohnwu.magisk.arch.viewModel
|
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
|
||||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler.REQUEST
|
import com.topjohnwu.magisk.core.su.SuCallbackHandler.REQUEST
|
||||||
import com.topjohnwu.magisk.databinding.ActivityRequestBinding
|
import com.topjohnwu.magisk.databinding.ActivityRequestBinding
|
||||||
@@ -19,7 +20,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
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 layoutRes: Int = R.layout.activity_request
|
||||||
override val viewModel: SuRequestViewModel by viewModel()
|
override val viewModel: SuRequestViewModel by viewModel()
|
@@ -17,19 +17,18 @@ import android.widget.Toast
|
|||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||||
|
import com.topjohnwu.magisk.core.AppContext
|
||||||
import com.topjohnwu.magisk.core.Config
|
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.data.magiskdb.PolicyDao
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
|
||||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
|
||||||
import com.topjohnwu.magisk.core.ktx.getLabel
|
import com.topjohnwu.magisk.core.ktx.getLabel
|
||||||
import com.topjohnwu.magisk.core.ktx.toast
|
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.ALLOW
|
||||||
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.DENY
|
import com.topjohnwu.magisk.core.model.su.SuPolicy.Companion.DENY
|
||||||
import com.topjohnwu.magisk.core.su.SuRequestHandler
|
import com.topjohnwu.magisk.core.su.SuRequestHandler
|
||||||
import com.topjohnwu.magisk.databinding.set
|
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.DieEvent
|
||||||
import com.topjohnwu.magisk.events.ShowUIEvent
|
import com.topjohnwu.magisk.events.ShowUIEvent
|
||||||
import com.topjohnwu.magisk.utils.TextHolder
|
import com.topjohnwu.magisk.utils.TextHolder
|
||||||
@@ -77,12 +76,8 @@ class SuRequestViewModel(
|
|||||||
|
|
||||||
fun grantPressed() {
|
fun grantPressed() {
|
||||||
cancelTimer()
|
cancelTimer()
|
||||||
if (ServiceLocator.biometrics.isEnabled) {
|
if (Config.suAuth) {
|
||||||
BiometricEvent {
|
AuthEvent { respond(ALLOW) }.publish()
|
||||||
onSuccess {
|
|
||||||
respond(ALLOW)
|
|
||||||
}
|
|
||||||
}.publish()
|
|
||||||
} else {
|
} else {
|
||||||
respond(ALLOW)
|
respond(ALLOW)
|
||||||
}
|
}
|
||||||
@@ -116,7 +111,7 @@ class SuRequestViewModel(
|
|||||||
// shared UID. We have no way to know where this request comes from.
|
// shared UID. We have no way to know where this request comes from.
|
||||||
icon = pm.defaultActivityIcon
|
icon = pm.defaultActivityIcon
|
||||||
title = "[SharedUID] ${info.sharedUserId}"
|
title = "[SharedUID] ${info.sharedUserId}"
|
||||||
packageName = info.sharedUserId
|
packageName = info.sharedUserId.toString()
|
||||||
} else {
|
} else {
|
||||||
val prefix = if (info.sharedUserId == null) "" else "[SharedUID] "
|
val prefix = if (info.sharedUserId == null) "" else "[SharedUID] "
|
||||||
icon = app.loadIcon(pm)
|
icon = app.loadIcon(pm)
|
@@ -12,6 +12,7 @@ import com.topjohnwu.magisk.arch.BaseFragment
|
|||||||
import com.topjohnwu.magisk.arch.viewModel
|
import com.topjohnwu.magisk.arch.viewModel
|
||||||
import com.topjohnwu.magisk.databinding.FragmentThemeMd2Binding
|
import com.topjohnwu.magisk.databinding.FragmentThemeMd2Binding
|
||||||
import com.topjohnwu.magisk.databinding.ItemThemeBindingImpl
|
import com.topjohnwu.magisk.databinding.ItemThemeBindingImpl
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
class ThemeFragment : BaseFragment<FragmentThemeMd2Binding>() {
|
class ThemeFragment : BaseFragment<FragmentThemeMd2Binding>() {
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ class ThemeFragment : BaseFragment<FragmentThemeMd2Binding>() {
|
|||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
|
|
||||||
activity?.title = getString(R.string.section_theme)
|
activity?.title = getString(CoreR.string.section_theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -0,0 +1,14 @@
|
|||||||
|
package com.topjohnwu.magisk.utils
|
||||||
|
|
||||||
|
import android.content.ContentResolver
|
||||||
|
import android.provider.Settings
|
||||||
|
|
||||||
|
class AccessibilityUtils {
|
||||||
|
companion object {
|
||||||
|
fun isAnimationEnabled(cr: ContentResolver): Boolean {
|
||||||
|
return !(Settings.Global.getFloat(cr, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f) == 0.0f
|
||||||
|
&& Settings.Global.getFloat(cr, Settings.Global.TRANSITION_ANIMATION_SCALE, 1.0f) == 0.0f
|
||||||
|
&& Settings.Global.getFloat(cr, Settings.Global.WINDOW_ANIMATION_SCALE, 1.0f) == 0.0f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -14,7 +14,7 @@ import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
|||||||
import com.google.android.material.circularreveal.CircularRevealCompat
|
import com.google.android.material.circularreveal.CircularRevealCompat
|
||||||
import com.google.android.material.circularreveal.CircularRevealWidget
|
import com.google.android.material.circularreveal.CircularRevealWidget
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
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
|
import kotlin.math.hypot
|
||||||
|
|
||||||
object MotionRevealHelper {
|
object MotionRevealHelper {
|
||||||
@@ -63,7 +63,9 @@ object MotionRevealHelper {
|
|||||||
it.interpolator = FastOutSlowInInterpolator()
|
it.interpolator = FastOutSlowInInterpolator()
|
||||||
it.addListener(onStart = { show() }, onEnd = { if (revealInfo.radius != 0f) hide() })
|
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 maxX = revealInfo.centerX - marginEnd - measuredWidth / 2f
|
||||||
val targetX = if (revealInfo.radius == 0f) 0f else maxX * rtlMod
|
val targetX = if (revealInfo.radius == 0f) 0f else maxX * rtlMod
|
||||||
val moveX = ObjectAnimator.ofFloat(this, View.TRANSLATION_X, targetX)
|
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.google.android.material.shape.MaterialShapeDrawable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
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.DialogMagiskBaseBinding
|
||||||
import com.topjohnwu.magisk.databinding.DiffItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.ItemWrapper
|
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||||
@@ -42,7 +42,7 @@ class MagiskDialog(
|
|||||||
DialogMagiskBaseBinding.inflate(LayoutInflater.from(context))
|
DialogMagiskBaseBinding.inflate(LayoutInflater.from(context))
|
||||||
private val data = Data()
|
private val data = Data()
|
||||||
|
|
||||||
val activity: BaseActivity get() = ownerActivity as BaseActivity
|
val activity: UIActivity<*> get() = ownerActivity as UIActivity<*>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
binding.setVariable(BR.data, data)
|
binding.setVariable(BR.data, data)
|
@@ -3,6 +3,7 @@ package com.topjohnwu.magisk.view
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.databinding.DiffItem
|
import com.topjohnwu.magisk.databinding.DiffItem
|
||||||
import com.topjohnwu.magisk.databinding.RvItem
|
import com.topjohnwu.magisk.databinding.RvItem
|
||||||
|
import com.topjohnwu.magisk.core.R as CoreR
|
||||||
|
|
||||||
sealed class TappableHeadlineItem : RvItem(), DiffItem<TappableHeadlineItem> {
|
sealed class TappableHeadlineItem : RvItem(), DiffItem<TappableHeadlineItem> {
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ sealed class TappableHeadlineItem : RvItem(), DiffItem<TappableHeadlineItem> {
|
|||||||
// --- objects
|
// --- objects
|
||||||
|
|
||||||
object ThemeMode : TappableHeadlineItem() {
|
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
|
override val icon = R.drawable.ic_day_night
|
||||||
}
|
}
|
||||||
|
|
@@ -18,7 +18,7 @@
|
|||||||
<aapt:attr name="android:animation">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="500"
|
android:duration="500"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="500"
|
android:duration="500"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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">
|
<aapt:attr name="android:animation">
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:duration="300"
|
android:duration="300"
|
||||||
android:interpolator="@interpolator/fast_out_slow_in"
|
android:interpolator="@android:interpolator/fast_out_slow_in"
|
||||||
android:propertyName="pathData"
|
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: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"
|
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"
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user