Compare commits
	
		
			632 Commits
		
	
	
		
			appbase-v1
			...
			apputils
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 3eeb808e07 | |||
| 56a3e12521 | |||
|   | 6ce48c8881 | ||
| eb0881ae6b | |||
| c88dcd7316 | |||
|   | 0ab2fdea66 | ||
| ce83a08eb8 | |||
| 7679c9a0d9 | |||
|   | 23eca69a3c | ||
| 1362d7a5cf | |||
|   | 8963d2a5df | ||
|   | f2726ddc7a | ||
|   | fa09da4e56 | ||
|   | edc63c750b | ||
| 52185ed7da | |||
| 355a1c70e5 | |||
| a808310a7c | |||
|   | 839a9e2054 | ||
|   | 471ca23585 | ||
|   | 56be1767bb | ||
|   | b66d53da1b | ||
| b170085482 | |||
| 6e8ba3394d | |||
| b91fe3c16b | |||
| e30b7acfdb | |||
| 6221555dfe | |||
|   | c60eb29f4f | ||
|   | 3efcf40025 | ||
|   | 27e948b86d | ||
|   | ae4742f3e2 | ||
|   | d3312cbb29 | ||
|   | 58f3778dff | ||
|   | f5e2961445 | ||
|   | e4e9c31f02 | ||
|   | a02a7efe43 | ||
|   | 2220efd009 | ||
|   | 0bc0fdf8c2 | ||
|   | 6b7b07a6fd | ||
|   | 8f3417818d | ||
|   | ca280c7334 | ||
|   | 8172cf7b6f | ||
|   | 8014f4149c | ||
|   | 3c36ed589a | ||
|   | 9768103741 | ||
|   | 787b8f0d77 | ||
|   | 1d58126fd8 | ||
|   | 7b5a3d2d71 | ||
|   | a988a9d4f6 | ||
|   | 04a67e666b | ||
|   | 348edc8aaf | ||
|   | 5970ae33c8 | ||
|   | 91a44f48ef | ||
|   | c66e9a090b | ||
|   | 7a14b55247 | ||
|   | fab68f16c8 | ||
|   | 3a97c6135f | ||
|   | cdad017d8c | ||
|   | bf84382963 | ||
|   | 34601fc5b1 | ||
|   | a40dbcfb61 | ||
|   | 4d344b299b | ||
|   | 37b0867d34 | ||
|   | cdfbb082d2 | ||
|   | 7e476894a7 | ||
|   | 0e8ae2e020 | ||
|   | 48623a2805 | ||
|   | b505156211 | ||
|   | 91b30fb576 | ||
|   | ab3ac72d54 | ||
|   | 73285c8779 | ||
|   | fa338ec8c7 | ||
|   | 7a3a1f4bcd | ||
|   | ea65810e7d | ||
|   | ad991e3da2 | ||
|   | 7e263447c8 | ||
|   | 80201e8370 | ||
|   | ea0473606a | ||
|   | 870e9a94fb | ||
|   | 2421ecb943 | ||
|   | 687fff7216 | ||
|   | 50d4cd830b | ||
|   | 2079822c00 | ||
|   | 297c76f328 | ||
|   | 43b18ee662 | ||
|   | 3ec3a4cfc2 | ||
|   | 2c10a9f38c | ||
|   | e62888636e | ||
|   | 364980dd02 | ||
|   | 0e155e4f3a | ||
|   | 89febba5a9 | ||
|   | 653330f8e1 | ||
|   | 386c73effc | ||
|   | b385583c5a | ||
|   | e7a9be2f56 | ||
|   | b27f7b0080 | ||
|   | 0a440419ff | ||
|   | 9e189ed5ac | ||
|   | 0fb6aadc72 | ||
|   | 46f3315b02 | ||
|   | c0ff228845 | ||
|   | a0fe8f17a8 | ||
|   | 16bd40fc59 | ||
|   | ffaf683c54 | ||
|   | 26f5f8d3db | ||
|   | 917e25cdc8 | ||
|   | 707bed52c7 | ||
|   | 3795cf8631 | ||
|   | b374f3117a | ||
|   | d581cd9842 | ||
|   | cef50d087d | ||
|   | 6d9adc124e | ||
|   | 52f738b45b | ||
|   | 9ece6778b7 | ||
|   | b7f8b76ace | ||
|   | 326e5fa68e | ||
|   | e9c8f9029e | ||
|   | c00bfa1292 | ||
|   | 11ee4dcf27 | ||
|   | 8974e24dce | ||
|   | 89142e379c | ||
|   | dabc671c27 | ||
|   | ed849e92d1 | ||
|   | 42d2522927 | ||
|   | 6a52b2a8c3 | ||
|   | 02ed5bd5d1 | ||
|   | b685665d0c | ||
|   | 1b030a2855 | ||
|   | dd577f1765 | ||
|   | 0f8350600d | ||
|   | 1777ebb8dc | ||
|   | 2b99f707e7 | ||
|   | 068c94e749 | ||
|   | 0b3bc7e296 | ||
|   | 6ef747bcf8 | ||
|   | a8e843c388 | ||
|   | d3fd593cb0 | ||
|   | 3aec176b8b | ||
|   | 5960f76238 | ||
|   | 1a118da827 | ||
|   | f73cad6f3e | ||
|   | 7130ecf023 | ||
|   | 953c8f08cd | ||
|   | 87b7557f72 | ||
|   | 77f5a156f8 | ||
|   | b34ea40536 | ||
|   | d202a3443d | ||
|   | 8c532c885f | ||
|   | 5fc4cb5f74 | ||
|   | 2a590a99fb | ||
|   | c6ad707ca2 | ||
|   | ee13a43fb6 | ||
|   | 5fbe1d8f71 | ||
|   | 38fe941a8b | ||
|   | e13c8e7af0 | ||
|   | a4988b5b68 | ||
|   | 04df902b6b | ||
|   | 33c71ea868 | ||
|   | 5507126f6b | ||
|   | d381c29452 | ||
|   | ba861d910e | ||
|   | f5d9aafe43 | ||
|   | e80d7e7b03 | ||
|   | 6e0a833fde | ||
|   | c596ee5fa4 | ||
|   | 5e99f1278e | ||
|   | b7158d1ebd | ||
|   | 9b51250ebf | ||
|   | eb61eb7306 | ||
|   | 31ad66685c | ||
|   | beb561ad6a | ||
|   | 8869265d60 | ||
|   | 2739627aff | ||
|   | 58e0be9cf4 | ||
|   | 9e9402f84e | ||
|   | ec18330022 | ||
|   | 8bb80ef575 | ||
|   | c1e6e32809 | ||
|   | 3e7722e2c0 | ||
|   | a1707e73b5 | ||
|   | 9dcbaa0d75 | ||
|   | 23920a7ff1 | ||
|   | 17c373c490 | ||
|   | 5f7c94b349 | ||
|   | c2b739d345 | ||
|   | 67a05cd457 | ||
|   | 554ab758bf | ||
|   | 20e118cd34 | ||
|   | f370ae8ffb | ||
|   | c92c874ea1 | ||
|   | 90a6116c0a | ||
|   | 45208ecbb1 | ||
|   | c28d655fe3 | ||
|   | 4b5905f74e | ||
|   | 6bd01780ec | ||
|   | a6699262f8 | ||
|   | 07b5e66875 | ||
|   | 91f5cf9051 | ||
|   | ea2d38defc | ||
|   | e430b7abe4 | ||
|   | 945eadb617 | ||
|   | c5bffc5eef | ||
|   | 88597fe407 | ||
|   | 53f985533a | ||
|   | a3950f13ad | ||
|   | c878e9dc02 | ||
|   | f2f7cab330 | ||
|   | 0e3b9dc760 | ||
|   | 6c8b0dcfa5 | ||
|   | 7de8a4f084 | ||
|   | 219c6614be | ||
|   | 0f5bb020b9 | ||
|   | 7794ff80ec | ||
|   | 7463ad3352 | ||
|   | 69187e3ed0 | ||
|   | 753032efed | ||
|   | 2b4c43c9af | ||
|   | 711c98d556 | ||
|   | 202205588a | ||
|   | 42c4978b44 | ||
|   | 1a2b7b862d | ||
|   | 8730f434dd | ||
|   | eb253b374f | ||
|   | c4e88e9593 | ||
|   | 08d9d92ae4 | ||
|   | 74841c08dc | ||
|   | 945bacb825 | ||
|   | 0e464495fd | ||
|   | f8944490f8 | ||
|   | 733af004f6 | ||
|   | c03568e1f5 | ||
|   | a0575a5e8b | ||
|   | 0e57ce679e | ||
|   | f9211a8eb4 | ||
|   | 4c31ff9b54 | ||
|   | 8cf610962e | ||
|   | 3071d186ec | ||
|   | df10306059 | ||
|   | ccdb9c5abd | ||
|   | f27209ab87 | ||
|   | e8682ce410 | ||
|   | 2e4003dae0 | ||
|   | 198b0975ce | ||
|   | 24a578a9d2 | ||
|   | 46de24447f | ||
|   | 2a819e94e4 | ||
|   | 6635358ec5 | ||
|   | ac1c008035 | ||
|   | b124487cb1 | ||
|   | 9621d35f79 | ||
|   | 17de0832a6 | ||
|   | f53b222b7f | ||
|   | 0c0cde8406 | ||
|   | 46967065c0 | ||
|   | 8edbff5ac1 | ||
|   | 434f8a8549 | ||
|   | c04be60b13 | ||
|   | 641098f8fb | ||
|   | dba54ac4b2 | ||
|   | c6cd779889 | ||
|   | dfb1692a04 | ||
|   | c83c8f66b3 | ||
|   | cd7b5f38bf | ||
|   | 0c2e73b82e | ||
|   | 7b1838ff8e | ||
|   | 73ff3d1726 | ||
|   | a69572e216 | ||
|   | fa79c3f807 | ||
|   | fde4b275f7 | ||
|   | d66d9373ff | ||
|   | f32ed94e4e | ||
|   | 1320984829 | ||
|   | abf1e5ba42 | ||
|   | 1cd2f88038 | ||
|   | 3f6e583d68 | ||
|   | 271456bfcd | ||
|   | ee5458d82c | ||
|   | 3a83367f71 | ||
|   | 74b9350a6a | ||
|   | d2858f23f7 | ||
|   | 40a5b9c339 | ||
|   | fd79113572 | ||
|   | 9b911b583c | ||
|   | 37817c3e8c | ||
|   | 0b5402f5f3 | ||
|   | bea22e3853 | ||
|   | 7e2ad0c01d | ||
|   | 476ce02fc8 | ||
|   | bc697279ad | ||
|   | dee01f1179 | ||
|   | a500decc7a | ||
|   | 5099d00050 | ||
|   | 515d14e896 | ||
|   | f630e27ed8 | ||
|   | cd7ed01216 | ||
|   | bb24bbfbd1 | ||
|   | 2ba2f88510 | ||
|   | db3a3644a8 | ||
|   | 556bfa7024 | ||
|   | 4842a1ec30 | ||
|   | 89dac91cc6 | ||
|   | 3809c1bcab | ||
|   | b0388a2972 | ||
|   | bd5a1f18ce | ||
|   | 99798b4816 | ||
|   | f93b6047a8 | ||
|   | daa3f858a0 | ||
|   | 3fded32426 | ||
|   | 8f85006040 | ||
|   | e28b0bd75e | ||
|   | af1d6d3439 | ||
|   | 470d1ffa1f | ||
|   | 49ae869df1 | ||
|   | 77e98bafe4 | ||
|   | ff14d0c0c3 | ||
|   | 950be3a182 | ||
|   | 1f20fca9be | ||
|   | 8d29d11078 | ||
|   | 7534881f50 | ||
|   | ef992dcd7c | ||
|   | 71c1baa4ba | ||
|   | 9e149037db | ||
|   | 89df24f736 | ||
|   | 2118495bc8 | ||
|   | 1dd614bd68 | ||
|   | b793c74e81 | ||
|   | 8d1872a893 | ||
|   | 5c58ee34e7 | ||
|   | e530403af7 | ||
|   | 264ab802c5 | ||
|   | 7c1832dc05 | ||
|   | 9a0ee889ba | ||
|   | c40066ca4d | ||
|   | 5348d1ef6d | ||
|   | 063c997bbb | ||
|   | 1376ca7ebb | ||
|   | 92e271b569 | ||
|   | a5083cc52f | ||
|   | 0692d4efb2 | ||
|   | f10438d3d3 | ||
|   | 1e697bc12d | ||
|   | d5a3c626b3 | ||
|   | 56692db142 | ||
|   | 934d54963a | ||
|   | c105123e7b | ||
|   | d8c534bbc8 | ||
|   | 6cce9c4d3f | ||
|   | df18c34976 | ||
|   | 22ca83b5b7 | ||
|   | 98233ce148 | ||
|   | 41fd9b171b | ||
|   | 330e5032df | ||
|   | 76420ff5f4 | ||
|   | ee3553716c | ||
|   | 02da4c3db9 | ||
|   | d689db61ff | ||
|   | 2b090e5c8e | ||
|   | 309214ecf3 | ||
|   | d29c9de3b4 | ||
|   | d7efdb6c02 | ||
|   | 20b36dd63b | ||
|   | a40450c085 | ||
|   | e7a7a4438c | ||
|   | 3e6de13fa3 | ||
|   | af848809e9 | ||
|   | 2c7026a635 | ||
|   | 6278c3f945 | ||
|   | bc3a320433 | ||
|   | e03b8d4745 | ||
|   | d5fb348134 | ||
|   | 5c7437b19c | ||
|   | bf09def10b | ||
|   | 8431d7dfa9 | ||
|   | 6aadaf87af | ||
|   | 6a2943420f | ||
|   | dc704e292a | ||
|   | 1087a7837c | ||
|   | 59876a2353 | ||
|   | 053b45e87e | ||
|   | 58e49ed371 | ||
|   | 90a6eb266b | ||
|   | f0a564c9bb | ||
|   | 46b21331af | ||
|   | 6221cc30ac | ||
|   | 8489ee6447 | ||
|   | 9205af4aa9 | ||
|   | 780e730a38 | ||
|   | 429499885b | ||
|   | fcf4ad2fc0 | ||
|   | 7635f6f084 | ||
|   | e49935f772 | ||
|   | 381ddf9e40 | ||
|   | 7774317c3b | ||
|   | 16f45aabe4 | ||
|   | 8190f4818f | ||
|   | f339733d4b | ||
|   | f770ea5aa0 | ||
|   | 0a993ccb9b | ||
|   | 9d0bdb803b | ||
|   | 9bd4c41b75 | ||
|   | af0b8859f0 | ||
|   | 275330f553 | ||
|   | 42256fd0e4 | ||
|   | fa72983f54 | ||
|   | 35825d5ead | ||
|   | 577237bc9e | ||
|   | 8ef41b9f1b | ||
|   | 36733e362b | ||
|   | fbf71e6998 | ||
|   | 77bdf886e9 | ||
|   | 2a11205468 | ||
|   | bb9f46373a | ||
|   | af797743d4 | ||
|   | 1b37f1bd11 | ||
|   | 00177284c1 | ||
|   | 178e00f8b4 | ||
|   | 743a5d5299 | ||
|   | 30f75f2394 | ||
|   | 9d66934694 | ||
|   | c7177f5fa5 | ||
|   | 9e8263ae8f | ||
|   | 5ee9da1982 | ||
|   | f59f7676b7 | ||
|   | 19b8251182 | ||
|   | 4dadb15c0c | ||
|   | 21b5487513 | ||
|   | f49c8141a8 | ||
|   | 6f3ce092ca | ||
|   | 29785be88d | ||
|   | bf0a70e056 | ||
|   | 3f809e4c7a | ||
|   | 9c3c485ecd | ||
|   | 336511931d | ||
|   | d3da3304ee | ||
|   | a5295a0744 | ||
|   | 9b761b35ce | ||
|   | 5206f8781e | ||
|   | 2c0a5bfe65 | ||
|   | 49bce0f773 | ||
|   | 07c6778212 | ||
|   | 1cdad9ac7d | ||
|   | 986922c1fa | ||
|   | bff40d2a64 | ||
|   | c687b5513d | ||
|   | 13e0ad3f03 | ||
|   | be85ef923e | ||
|   | 9a3383a43b | ||
|   | d875b6965d | ||
|   | bc873852c2 | ||
|   | b032de55dc | ||
|   | 8fa20b56ec | ||
|   | 1ca93a610e | ||
|   | 6555346618 | ||
|   | df6633046c | ||
|   | 7d35d5a9b8 | ||
|   | ddce5646bd | ||
|   | 3607a99053 | ||
|   | b44e5575b3 | ||
|   | 6a101d8843 | ||
|   | c5e5e76bbf | ||
|   | 6d05808a2a | ||
|   | 2625ffe6a6 | ||
|   | 9c4c1320aa | ||
|   | 551b424960 | ||
|   | 1062c7d2ee | ||
|   | e958556073 | ||
|   | 466e061aa8 | ||
|   | 2f2512cd76 | ||
|   | d26de8f2f7 | ||
|   | 2e9b6ae263 | ||
|   | f0a29dc7a9 | ||
|   | 7c7554133b | ||
|   | 98f6d0019b | ||
|   | fc9c82921d | ||
|   | 1ac0ad96e1 | ||
|   | 125c2b4431 | ||
|   | 9060cb51ff | ||
|   | 7951d0a8d6 | ||
|   | ded775ae01 | ||
|   | 82258f1763 | ||
|   | 99bf53f27d | ||
|   | ddb6b53189 | ||
|   | 4a4e20a6bd | ||
|   | 4c0d825d7b | ||
|   | ae111b3a99 | ||
|   | 03ceaf3e2a | ||
|   | ae8da772c0 | ||
|   | b2555ebfd3 | ||
|   | 7ff2cab615 | ||
|   | 954139f0c9 | ||
|   | 027dc23060 | ||
|   | 82d9aabf33 | ||
|   | 640f0c39e9 | ||
|   | 9816167e87 | ||
|   | 512c321b76 | ||
|   | 482c007481 | ||
|   | 609182f909 | ||
|   | eb69a473a3 | ||
|   | 38e4deb425 | ||
|   | d06023d023 | ||
|   | cb486bb90c | ||
|   | 2cbf9e5669 | ||
|   | e045bbb71c | ||
|   | e772563fc0 | ||
|   | d5782da040 | ||
|   | 55ce968053 | ||
|   | 502d3ad23d | ||
|   | 103c1101ce | ||
|   | 03d4cf2efe | ||
|   | 15fa0ad506 | ||
|   | 0dfc7df4b5 | ||
|   | f33956c872 | ||
|   | 9283ad709f | ||
|   | 459fff1531 | ||
|   | b4fb680b8c | ||
|   | cf933da3aa | ||
|   | 2bd8947af1 | ||
|   | 28f2ada31a | ||
|   | 81669f03b3 | ||
|   | 5a1f1f2d73 | ||
|   | 0e4dc85dfa | ||
|   | 204642a5cd | ||
|   | daf10dd727 | ||
|   | 2005ba6aee | ||
|   | 6adc96449b | ||
|   | 4d8675f1f7 | ||
|   | 2467f3b5a8 | ||
|   | b8834627ae | ||
|   | 164c00ee0d | ||
|   | b34d777c9f | ||
|   | 2ce07bbcf3 | ||
|   | 7932e25def | ||
|   | 191de5c511 | ||
|   | d520c9ae06 | ||
|   | 933abbc261 | ||
|   | 14a161ab3f | ||
|   | 248b8084dc | ||
|   | 006cefea2a | ||
|   | ad1b6ca3e9 | ||
|   | 37c93658b3 | ||
|   | 65aae2146e | ||
|   | 58eba26eb5 | ||
|   | a32b10cdec | ||
|   | 4612593d88 | ||
|   | 0460613aea | ||
|   | e1dadfa41c | ||
|   | 1a7134711e | ||
|   | dabd1271fd | ||
|   | 0d3d691d8a | ||
|   | f3198de003 | ||
|   | df179242f0 | ||
|   | 1ae3fdf2b7 | ||
|   | 7edc341f15 | ||
|   | f1669f9e41 | ||
|   | 63b1d2dece | ||
|   | 6a0510e76c | ||
|   | 840da14438 | ||
|   | 31595fe1ae | ||
|   | 2c91d32e41 | ||
|   | 58dabb7138 | ||
|   | 3432575aa7 | ||
|   | c302179960 | ||
|   | df55608eb3 | ||
|   | b64a229ab1 | ||
|   | d507d4ac06 | ||
|   | e815c08970 | ||
|   | d780116031 | ||
|   | fa43d43110 | ||
|   | 8f8e7d98c7 | ||
|   | af39f98a51 | ||
|   | 8dd41a0c3a | ||
|   | ca4814744f | ||
|   | 5a1d557683 | ||
|   | 39116f0912 | ||
|   | 5a9ee81c30 | ||
|   | 841d526b0d | ||
|   | 11d2db6bf9 | ||
|   | 93d8fa15db | ||
|   | 99ff741a22 | ||
|   | 5bc7581db1 | ||
|   | fde0712439 | ||
|   | a6b711b38b | ||
|   | d1703551f5 | ||
|   | d63f7d3d83 | ||
|   | 06b399846d | ||
|   | e06efea08e | ||
|   | 890ff6eda9 | ||
|   | e5a5eda9b6 | ||
|   | 174a052088 | ||
|   | fbd8441264 | ||
|   | fb92e9f673 | ||
|   | d34d1e2796 | ||
|   | 36fb8b41a4 | ||
|   | fe70a18547 | ||
|   | b61c63c426 | ||
|   | f02dc215ca | ||
|   | 1c27d0ccdc | ||
|   | 803745d12e | ||
|   | a66be9cd37 | ||
|   | 46e4ee7fb7 | ||
|   | b2b959232c | ||
|   | b11f814c41 | ||
|   | 1e991aed7e | ||
|   | f56125f82a | ||
|   | 4ff54c785e | ||
|   | b961468e1e | ||
|   | 575ef9aac0 | ||
|   | 16b118f83b | ||
|   | 1eeba4e4c6 | ||
|   | 66eb8e06ea | ||
|   | 51775620db | ||
|   | deaa9caadd | ||
|   | 58af5ba074 | ||
|   | 19743d30ef | ||
|   | 3c2b720e20 | ||
|   | 5a052e4b22 | ||
|   | 4ccf6824a6 | ||
|   | 508c8b0b97 | ||
|   | 0d21994291 | ||
|   | 5714aed761 | ||
|   | f04f5cf77c | ||
|   | 6ccbaf8c32 | ||
|   | 33b7b65239 | ||
|   | 664d14ad84 | ||
|   | 47cb393f76 | ||
|   | 6495f1c66e | ||
|   | f0c52d1e02 | ||
|   | d948f31331 | ||
|   | e1b3087020 | ||
|   | 03e21ab81c | ||
|   | ac72132969 | ||
|   | cedb5f521b | ||
|   | 396df6713c | 
							
								
								
									
										16
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -87,19 +87,15 @@ lint/tmp/ | ||||
| # Android Profiling | ||||
| *.hprof | ||||
|  | ||||
| # Custom | ||||
| .androidide | ||||
| # 忽略 Lint 输出文件 | ||||
| lint-results.xml | ||||
| lint-results.html | ||||
| winboll.properties | ||||
| local.properties | ||||
|  | ||||
| ## 忽略 AndroidIDE 临时文件夹 | ||||
| .androidide | ||||
|  | ||||
| ## 忽略模块应用编译配置 | ||||
| /settings.gradle | ||||
| /gradle.properties | ||||
|  | ||||
| ## 忽略 srv 纠结问题 | ||||
| /srv/ | ||||
|  | ||||
| ## 忽略 winboll-x 文件夹 | ||||
| /winboll-x/ | ||||
| /winboll.properties | ||||
| /local.properties | ||||
|   | ||||
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,3 @@ | ||||
| [submodule "winboll-x"] | ||||
| 	path = winboll-x | ||||
| 	url = https://gitea.winboll.cc/Studio/WinBollX.git | ||||
| [submodule "libjc/jcc/libs"] | ||||
| 	path = libjc/jcc/libs | ||||
| 	url = https://gitea.winboll.cc/Studio/APP_libjc_jcc_libs.git | ||||
|   | ||||
| @@ -1,3 +0,0 @@ | ||||
| #!/bin/usr/bash | ||||
| ## Change Back To Beta KeyStore in keystore module. | ||||
| cd keystore;git reset --hard f5bc75ff45fcb8894b5bd3f49b91bdd8fe3c317e;cd .. | ||||
| @@ -1,3 +0,0 @@ | ||||
| #!/bin/usr/bash | ||||
| ## Change Back To StageMG KeyStore in keystore module. | ||||
| cd keystore;git reset --hard d22519b11253f85f495400b01b6373e9657defb4;cd .. | ||||
| @@ -113,10 +113,10 @@ if [[ $? -eq 0 ]]; then | ||||
|     # 如果Git已经提交了所有代码就执行标签和应用发布操作 | ||||
|  | ||||
|     # 预先询问是否添加工作流标签 | ||||
|     echo "Add Github Workflows Tag? (yes/No)" | ||||
| 	result=$(askAddWorkflowsTag) | ||||
| 	nAskAddWorkflowsTag=$? | ||||
| 	echo $result | ||||
|     #echo "Add Github Workflows Tag? (yes/No)" | ||||
| 	#result=$(askAddWorkflowsTag) | ||||
| 	#nAskAddWorkflowsTag=$? | ||||
| 	#echo $result | ||||
|  | ||||
|     # 发布应用 | ||||
| 	echo "Publishing WinBoLL APK ..." | ||||
| @@ -138,17 +138,17 @@ if [[ $? -eq 0 ]]; then | ||||
| 	fi | ||||
|      | ||||
|     # 添加 GitHub 工作流标签 | ||||
| 	if [[ $nAskAddWorkflowsTag -eq 1 ]]; then | ||||
| 	#if [[ $nAskAddWorkflowsTag -eq 1 ]]; then | ||||
| 	    # 如果用户选择添加工作流标签 | ||||
|     	result=$(addWorkflowsTag $1) | ||||
| 		if [[ $? -eq 0 ]]; then | ||||
| 		    echo $result | ||||
|     	#result=$(addWorkflowsTag $1) | ||||
| 		#if [[ $? -eq 0 ]]; then | ||||
| 		#    echo $result | ||||
| 		    # 工作流标签添加成功 | ||||
| 		else | ||||
| 			echo -e "${0}: addWorkflowsTag $1\n${result}\nAdd workflows tag cancel." | ||||
| 			exit 1 # addWorkflowsTag 异常 | ||||
| 		fi | ||||
| 	fi | ||||
| 		#else | ||||
| 			#echo -e "${0}: addWorkflowsTag $1\n${result}\nAdd workflows tag cancel." | ||||
| 			#exit 1 # addWorkflowsTag 异常 | ||||
| 		#fi | ||||
| 	#fi | ||||
| 	 | ||||
| 	## 清理更新描述文件内容 | ||||
| 	echo "" > $1/app_update_description.txt | ||||
|   | ||||
| @@ -2,6 +2,11 @@ | ||||
| // | ||||
|  | ||||
| android { | ||||
| 	def winbollProps = new Properties() | ||||
|     def winbollPropsFile = rootProject.file("${winbollFilePath}") | ||||
|     assert(winbollPropsFile.exists()) | ||||
|     winbollProps.load(new FileInputStream(winbollPropsFile)) | ||||
|      | ||||
|     // 读取秘钥配置文件 | ||||
|     // | ||||
|     def keyProps = new Properties() | ||||
| @@ -122,6 +127,7 @@ android { | ||||
|                                     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|                                     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|                                     fos.close(); | ||||
| 									println "\n\n>>> Project build.properties saved.\n\n"; | ||||
|                                      | ||||
|                                     if(winbollBuildProps['libraryProject'] != "") { | ||||
|                                         // 如果应用 build.properties 文件设置了类库模块项目文件名 | ||||
| @@ -133,14 +139,15 @@ android { | ||||
|                                         java.nio.file.Path targetFilePath = libraryProjectBuildPropsFile.toPath(); | ||||
|                                         // 使用copyTo()方法复制文件,如果目标文件存在会被覆盖,可选参数可以选择不覆盖 | ||||
| 	                                    java.nio.file.Files.copy(sourceFilePath, targetFilePath, java.nio.file.StandardCopyOption.REPLACE_EXISTING); | ||||
| 										 | ||||
| 										println "\n\n>>> Library Project build.properties saved.\n\n"; | ||||
|                                     } | ||||
|                                 } | ||||
|                             } | ||||
|                              | ||||
|                             // 如果正在发布,就拷贝到 WinBoLL 标签管理文件夹 | ||||
|                             // 如果正在发布,就拷贝到 WinBoLL 标签管理文件夹,和处理 Git 仓库管理任务。 | ||||
|                             // | ||||
|                             if((variant.flavorName == "stage"&&variant.buildType.name == "debug") | ||||
|                                 || (variant.flavorName == "stage"&&variant.buildType.name == "release")){ | ||||
|                             if(variant.flavorName == "stage"&&variant.buildType.name == "release"){ | ||||
|                                 // 发布 APK 文件 | ||||
|                                 // | ||||
|                                 // 截取版本号的版本字段为短版本名 | ||||
| @@ -221,6 +228,7 @@ android { | ||||
|                                     } | ||||
|                                      | ||||
|                                     // 提交新的编译标志配置 | ||||
| 									println 'exec bashCommitAppPublishBuildFlagInfoFilePath ...' | ||||
|                                     def resultCommitBuildFlag = exec { | ||||
|                                         commandLine 'bash', '--', "${RootProjectDir}/${bashCommitAppPublishBuildFlagInfoFilePath}", "${RootProjectDir}", "${versionName}", variant.buildType.name , rootProject.name | ||||
|                                     } | ||||
| @@ -228,22 +236,78 @@ android { | ||||
|                                     assert(resultCommitBuildFlag.getExitValue() == 0) | ||||
|                                 } | ||||
|                             } //  if(variant.buildType.name == "release"){ | ||||
|                              | ||||
|                             // 如果公共目录存在就拷贝到公共目录并重命名为app.apk | ||||
|                             // | ||||
|                             File outCommonDir = new File("/sdcard/AppProjects") | ||||
|                             String commandAPKName = "app.apk" | ||||
|                             if(outCommonDir.exists()) { | ||||
|                                 copy{ | ||||
|                                     from file.outputFile | ||||
|                                     into outCommonDir | ||||
|                                     rename { | ||||
|                                         String fileName -> "${commandAPKName}" | ||||
| 							 | ||||
| 							// 如果正在调试发布版,就只生成和输出APK文件,不处理 Git 仓库提交与更新问题。 | ||||
| 							// | ||||
| 					        if(variant.flavorName == "stage"&&variant.buildType.name == "debug"){ | ||||
|                                 // 发布 APK 文件 | ||||
|                                 // | ||||
|                                 // 截取版本号的版本字段为短版本名 | ||||
|                                 String szVersionName = "${versionName}" | ||||
|                                 String[] szlistTemp = szVersionName.split("-") | ||||
|                                 String szShortVersionName = szlistTemp[0] | ||||
|                                 //String szCommonTagAPKName = "${rootProject.name}_" + szShortVersionName + ".apk" | ||||
|                                 String szCommonTagAPKName = project.rootDir.name + "_" + szShortVersionName + ".apk" | ||||
|                                 println "CommonTagAPKName is : " + szCommonTagAPKName | ||||
|                                  | ||||
|                                 //File outTagDir = new File(fWinBoLLStudioDir, "/${rootProject.name}/tag/") | ||||
|                                 File outTagDir = new File(fWinBoLLStudioDir, "/" + project.rootDir.name + "/${variant.buildType.name}/") | ||||
|                                 // 创建目标路径目录 | ||||
|                                 if(!outTagDir.exists()) { | ||||
|                                     outTagDir.mkdirs(); | ||||
|                                     println "Output Folder Created.(Tags) : " + outTagDir.getAbsolutePath() | ||||
|                                 } | ||||
|                                  | ||||
|                                 if(outTagDir.exists()) { | ||||
|                                     File targetAPK = new File(outTagDir, "${szCommonTagAPKName}") | ||||
|                                     if(targetAPK.exists()) { | ||||
|                                         // 标签版本APK文件已经存在,构建拷贝任务停止 | ||||
| 										println '如果是在调试 Stage 版应用包构建,请删除(注:在debug目录)现有的 Stage 应用包('+targetAPK.getAbsolutePath()+')。再编译一次。' | ||||
|                                         assert (!targetAPK.exists()) | ||||
|                                         // 可选择删除并继续输出APK文件 | ||||
|                                         //delete targetAPK | ||||
|                                     } | ||||
|                                     println "Output APK (Common): " + outCommonDir.getAbsolutePath() + "/${commandAPKName}" | ||||
|                                     // 复制一个备份 | ||||
|                                     copy{ | ||||
|                                         from file.outputFile | ||||
|                                         into outTagDir | ||||
|                                         rename { | ||||
|                                             String fileName -> "${outputFileName}" | ||||
|                                         } | ||||
|                                         println "Output APK (Tags): "+ outTagDir.getAbsolutePath() + "/${outputFileName}" | ||||
|                                     } | ||||
|                                     // 复制一个并重命名为短版本名 | ||||
|                                     copy{ | ||||
|                                         from file.outputFile | ||||
|                                         into outTagDir | ||||
|                                         rename { | ||||
|                                             String fileName -> "${szCommonTagAPKName}" | ||||
|                                         } | ||||
|                                         println "Output APK (Tags): "+ outTagDir.getAbsolutePath() + "/${szCommonTagAPKName}" | ||||
|                                     } | ||||
|                                      | ||||
|                                     //不保存编译标志配置 | ||||
|                                 } | ||||
|                             } | ||||
|                              | ||||
|                             // 如果配置了APK额外输出路径,就复制一份拷贝到额外路径。 | ||||
|                             // | ||||
| 							if(winbollProps['ExtraAPKOutputPath'] != null ) { | ||||
|                                 File apkFile = new File(winbollProps['ExtraAPKOutputPath']) | ||||
| 								File outCommonDir = apkFile.getParentFile(); | ||||
|                                 String commandAPKName = apkFile.getName(); | ||||
|                                 if(outCommonDir.exists()) { | ||||
|                                     copy{ | ||||
|                                         from file.outputFile | ||||
|                                         into outCommonDir | ||||
|                                         rename { | ||||
|                                             String fileName -> "${commandAPKName}" | ||||
|                                         } | ||||
|                                         println "Output APK (Common): " + outCommonDir.getAbsolutePath() + "/${commandAPKName}" | ||||
|                                     } | ||||
|                                 } | ||||
| 						    } | ||||
|                              | ||||
|                          | ||||
|                     } | ||||
| 	            }// End of (variant.getAssembleProvider().get().doLast {) | ||||
|   | ||||
							
								
								
									
										49
									
								
								GenKeyStore/gen_debug_keystore.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								GenKeyStore/gen_debug_keystore.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| #!/bin/bash | ||||
| # 应用秘钥创建脚本 | ||||
| # Linux 命令行创建JKS秘钥,alias和keyAlias可配置,文件名含时间戳 | ||||
|  | ||||
| # 可配置参数(按需修改) | ||||
| ALIAS="WinBoLL.CC_Debug"  # 别名(与keyAlias一致) | ||||
| STORE_PASS="androiddebugkey" | ||||
| KEY_PASS="androiddebugkey" | ||||
| COUNTRY="CN"        # 国家代码 | ||||
|  | ||||
| # 获取当前时间戳 | ||||
| TIMESTAMP=$(date +%Y%m%d%H%M%S) | ||||
| FILENAME="${ALIAS}_${TIMESTAMP}.jks" | ||||
| STORENAME="${ALIAS}_${TIMESTAMP}.keystore" | ||||
|  | ||||
| # 生成JKS文件(alias与keyAlias同步) | ||||
| keytool -genkeypair \ | ||||
|   -alias "${ALIAS}" \ | ||||
|   -keyalg RSA \ | ||||
|   -keysize 2048 \ | ||||
|   -validity 1 \ | ||||
|   -keystore "${FILENAME}" \ | ||||
|   -dname "CN=WBFans, OU=Studio, O=WinBoLL, L=Shanwei, ST=Guangdong, C=${COUNTRY}" \ | ||||
|   -storepass "${STORE_PASS}" \ | ||||
|   -keypass "${KEY_PASS}" | ||||
|  | ||||
| # 写入配置文件 | ||||
| cat <<EOF > ${STORENAME} | ||||
| keyAlias=${ALIAS} | ||||
| keyPassword=${KEY_PASS} | ||||
| storeFile=../appkey.jks | ||||
| storePassword=${STORE_PASS} | ||||
| EOF | ||||
|  | ||||
| echo "已生成秘钥:${FILENAME}" | ||||
| echo "配置已写入 ${STORENAME}(keyAlias=${ALIAS})" | ||||
|  | ||||
| # 询问是否复制文件 | ||||
| read -p "是否需要将文件复制为 appkey.jks 和 appkey.keystore?(y/n): " CONFIRM | ||||
|  | ||||
| if [[ $CONFIRM =~ ^[Yy]$ ]]; then | ||||
|   # 复制 jks 文件为 appkey.jks | ||||
|   cp -v ${FILENAME} ../appkey.jks | ||||
|   # 复制 keystore 文件为 appkey.keystore | ||||
|   cp -v ${STORENAME} ../appkey.keystore | ||||
|   echo "文件复制完成" | ||||
| else | ||||
|   echo "已取消文件复制" | ||||
| fi | ||||
							
								
								
									
										210
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										210
									
								
								LICENSE
									
									
									
									
									
								
							| @@ -1,73 +1,201 @@ | ||||
| Apache License | ||||
| Version 2.0, January 2004 | ||||
| http://www.apache.org/licenses/ | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
| 1. Definitions. | ||||
|    1. Definitions. | ||||
|  | ||||
| "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
| "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
| "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
| "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
| "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
| "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
| "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
| "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
| "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
| "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
| 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
| 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
| 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|      (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|      (b) You must cause any modified files to carry prominent notices stating that You changed the files; and | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|      (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|      (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|      You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
| 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
| 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
| 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
| 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
| 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
| END OF TERMS AND CONDITIONS | ||||
|    END OF TERMS AND CONDITIONS | ||||
|  | ||||
| APPENDIX: How to apply the Apache License to your work. | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
|  | ||||
| To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!)  The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "[]" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
|  | ||||
| Copyright 2024 ZhanGSKen | ||||
|    Copyright [yyyy] [name of copyright owner] | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
| http://www.apache.org/licenses/LICENSE-2.0 | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
|   | ||||
							
								
								
									
										33
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,4 +1,8 @@ | ||||
| # ☁ ☁ ☁ WinBoLL APP ☁ ☁ ☁ ☁ ☁ ☁   ☁ ☁   ☁  ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ ☁ ☁  | ||||
| # OriginMaster | ||||
| 【OriginMaster】WinBoLL 源生态计划。正如话,我需要一个 Point, 去撬动成个地球。 | ||||
|  | ||||
| ######## | ||||
| ## ☁ ☁ ☁ WinBoLL APP ☁ ☁ ☁ ☁ ☁ ☁   ☁ ☁   ☁  ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ ☁ ☁  | ||||
| # ☁    ☁ WinBoLL Studio Android 应用开源项目。☁ ☁   ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ ☁  ☁ ☁ ☁  | ||||
| # ☁ ☁ ☁ WinBoLL 网站地址 https://www.winboll.cc/ ☁ ☁ ☁ ☁  ☁ ☁ ☁ ☁ | ||||
|  | ||||
| @@ -110,9 +114,12 @@ | ||||
|  | ||||
| # 本项目要实际运用需要注意以下几个步骤: | ||||
| # 在项目根目录下: | ||||
| ## 1. 项目模块编译环境设置(必须),settings.gradle-demo 要复制为 settings.gradle,并取消相应项目模块的注释。 | ||||
| ## 2. 项目 Android SDK 编译环境设置(可选),local.properties-demo 要复制为 local.properties,并按需要设置 Android SDK 目录。 | ||||
| ## 3. 类库型模块编译环境设置(可选),winboll.properties-demo 要复制为 winboll.properties,并按需要设置 WinBoLL Maven 库登录用户信息。 | ||||
| ## ★. 项目模块编译环境设置(必须),settings.gradle-demo 要复制为 settings.gradle,并取消相应项目模块的注释。 | ||||
| ## ★. 项目模块编译环境设置(必须) 在根目录拷贝 gradle.properties-androidx-demo 或者 gradle.properties-android-demo 文件为 gradle.properties。 | ||||
| ## ★. 项目 Android SDK 编译环境设置(可选),local.properties-demo 要复制为 local.properties,并按需要设置 Android SDK 目录。 | ||||
| ## ★. 应用签名密钥 keystore 设置问题。一般调试编译只需用【Termux】cd 进 GenKeyStore 目录执行 $ bash gen_debug_keystore.sh 命令即可完成设置。 | ||||
| ## ☆. 应用 WiBoLL 签名密钥配置问题<非必须考虑>。设置时需要 clone 【keystore】模块源码并拷贝模块目录的 appkey.jks 与 appkey.keystore 到项目根目录即可。 | ||||
| ## ☆. 类库型模块编译环境设置(可选),winboll.properties-demo 要复制为 winboll.properties,并按需要设置 WinBoLL Maven 库登录用户信息, 和 APK 文件额外输出路径。 | ||||
|  | ||||
|  | ||||
| # ☆类库型项目编译方法 | ||||
| @@ -121,7 +128,8 @@ | ||||
| 设置属性 libraryProject=<类库项目模块文件夹名称> | ||||
| ### 再编译测试项目 | ||||
| $ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称> | ||||
| #### 测试项目编译后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
| #### 测试项目编译后,编译器会复制一份 APK 到 路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
| #### 若是 winboll.properties 文件的 [ExtraAPKOutputPath] 属性设置了路径。编译器也会复制一份 APK 到这个路径。 | ||||
| ### 最后编译类库项目 | ||||
| $ bash .winboll/bashPublishLIBAddTag.sh <类库项目模块文件夹名称> | ||||
| #### 类库模块编译命令执行后,编译器会发布到 WinBoLL Nexus Maven 库:Maven 库地址可以参阅根项目目录配置 build.gradle 文件。 | ||||
| @@ -129,4 +137,17 @@ $ bash .winboll/bashPublishLIBAddTag.sh <类库项目模块文件夹名称> | ||||
| # ☆应用型项目编译方法 | ||||
| ## 直接调用以下命令编译应用型项目 | ||||
| $ bash .winboll/bashPublishAPKAddTag.sh <应用项目模块文件夹名称> | ||||
| #### 应用模块编译命令执行后,编译器会复制一份 APK 到以下路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
| #### 应用模块编译命令执行后,编译器会复制一份 APK 到 | ||||
| #### 测试项目编译后,编译器会复制一份 APK 到 路径:"/sdcard/WinBoLLStudio/APKs/<项目根目录名称>/tag/" 文件夹。 | ||||
| #### 若是 winboll.properties 文件的 [ExtraAPKOutputPath] 属性设置了路径。编译器也会复制一份 APK 到这个路径。 | ||||
|  | ||||
| ## ☆应用调试编译方法 | ||||
| 使用以下命令编译调试: | ||||
|  | ||||
| ### Beta调试使用: | ||||
| $ bash gradlew assembleBetaDebug | ||||
|  | ||||
| ### Stage调试使用: | ||||
| $ bash gradlew assembleStageDebug | ||||
|  | ||||
| ### 若是 winboll.properties 文件的 [ExtraAPKOutputPath] 属性设置了路径。编译器也会复制一份 APK 到这个路径。 | ||||
|   | ||||
							
								
								
									
										35
									
								
								aes/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								aes/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| # AES | ||||
|  | ||||
| #### 介绍 | ||||
| 安卓视图元素类库 | ||||
|  | ||||
| #### 软件架构 | ||||
| 适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。 | ||||
| 也适配安卓应用 [AndroidIDE] 的 Gradle 编译结构。 | ||||
|  | ||||
|  | ||||
| #### Gradle 编译说明 | ||||
| 调试版编译命令 :gradle assembleBetaDebug | ||||
| 阶段版编译命令 :bash .winboll/bashPublishAPKAddTag.sh aes | ||||
| 阶段版类库发布命令 :git pull &&bash .winboll/bashPublishLIBAddTag.sh libaes | ||||
|  | ||||
| #### 使用说明 | ||||
|  | ||||
| #### 参与贡献 | ||||
|  | ||||
| 1.  Fork 本仓库 | ||||
| 2.  新建 Feat_xxx 分支 | ||||
| 3.  提交代码 : ZhanGSKen(ZhanGSKen<zhangsken@188.com>) | ||||
| 4.  新建 Pull Request | ||||
|  | ||||
|  | ||||
| #### 特技 | ||||
|  | ||||
| 1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md | ||||
| 2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) | ||||
| 3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 | ||||
| 4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 | ||||
| 5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) | ||||
| 6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) | ||||
|  | ||||
| #### 参考文档 | ||||
| @@ -24,12 +24,12 @@ android { | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.aes" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 29 | ||||
|         targetSdkVersion 30 | ||||
|         versionCode 1 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // 项目模块目录的 build.gradle 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.2"  | ||||
|         versionName "15.9"  | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Thu Apr 03 11:14:05 HKT 2025 | ||||
| stageCount=7 | ||||
| #Sun Aug 31 23:40:17 HKT 2025 | ||||
| stageCount=4 | ||||
| libraryProject=libaes | ||||
| baseVersion=15.2 | ||||
| publishVersion=15.2.6 | ||||
| baseVersion=15.9 | ||||
| publishVersion=15.9.3 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.2.7 | ||||
| baseBetaVersion=15.9.4 | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| package cc.winboll.studio.aes; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/24 23:52:29 | ||||
|  * @Describe AES应用介绍窗口 | ||||
|  */ | ||||
| @@ -15,9 +15,9 @@ import androidx.appcompat.widget.Toolbar; | ||||
| import cc.winboll.studio.libaes.winboll.APPInfo; | ||||
| import cc.winboll.studio.libaes.winboll.AboutView; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBollActivity; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
|  | ||||
| public class AboutActivity extends WinBollActivity implements IWinBollActivity { | ||||
| public class AboutActivity extends AppCompatActivity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "AboutActivity"; | ||||
|  | ||||
| @@ -64,13 +64,13 @@ public class AboutActivity extends WinBollActivity implements IWinBollActivity { | ||||
|         ); | ||||
|         layout.addView(aboutView, params); | ||||
|  | ||||
|         GlobalApplication.getWinBollActivityManager().add(this); | ||||
|         GlobalApplication.getWinBoLLActivityManager().add(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         GlobalApplication.getWinBollActivityManager().registeRemove(this); | ||||
|         GlobalApplication.getWinBoLLActivityManager().registeRemove(this); | ||||
|     } | ||||
|  | ||||
|     public AboutView CreateAboutView() { | ||||
| @@ -79,11 +79,11 @@ public class AboutActivity extends WinBollActivity implements IWinBollActivity { | ||||
|         appInfo.setAppName("AES"); | ||||
|         appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll); | ||||
|         appInfo.setAppDescription("AES Description"); | ||||
|         appInfo.setAppGitName("APP"); | ||||
|         appInfo.setAppGitName("APPBase"); | ||||
|         appInfo.setAppGitOwner("Studio"); | ||||
|         appInfo.setAppGitAPPBranch(szBranchName); | ||||
|         appInfo.setAppGitAPPSubProjectFolder(szBranchName); | ||||
|         appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=AES"); | ||||
|         appInfo.setAppHomePage("https://discuz.winboll.cc/forum.php?mod=viewthread&tid=3&extra=page%3D1"); | ||||
|         appInfo.setAppAPKName("AES"); | ||||
|         appInfo.setAppAPKFolderName("AES"); | ||||
|         //appInfo.setIsAddDebugTools(false); | ||||
|   | ||||
| @@ -1,13 +1,14 @@ | ||||
| package cc.winboll.studio.aes; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/06/13 19:03:58 | ||||
|  * @Describe AES应用类 | ||||
|  */ | ||||
| import android.view.Gravity; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import com.hjq.toast.style.WhiteToastStyle; | ||||
|  | ||||
|  | ||||
| public class App extends GlobalApplication { | ||||
| @@ -21,8 +22,8 @@ public class App extends GlobalApplication { | ||||
|         // 初始化 Toast 框架 | ||||
|         ToastUtils.init(this); | ||||
|         // 设置 Toast 布局样式 | ||||
|         ToastUtils.setView(R.layout.view_toast); | ||||
|         //ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         //ToastUtils.setView(R.layout.view_toast); | ||||
|         ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         ToastUtils.setGravity(Gravity.BOTTOM, 0, 200); | ||||
|  | ||||
|     } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| package cc.winboll.studio.aes; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/06/13 19:05:52 | ||||
|  * @Describe 应用主窗口 | ||||
|  */ | ||||
| @@ -25,12 +25,12 @@ import cc.winboll.studio.libaes.unittests.TestAToolbarActivity; | ||||
| import cc.winboll.studio.libaes.unittests.TestDrawerFragmentActivity; | ||||
| import cc.winboll.studio.libaes.unittests.TestViewPageFragment; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBollActivity; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import com.a4455jkjh.colorpicker.ColorPickerDialog; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class MainActivity extends DrawerFragmentActivity implements IWinBollActivity { | ||||
| public class MainActivity extends DrawerFragmentActivity implements IWinBoLLActivity { | ||||
|  | ||||
|  | ||||
|     public static final String TAG = "MainActivity"; | ||||
| @@ -123,7 +123,7 @@ public class MainActivity extends DrawerFragmentActivity implements IWinBollActi | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         int nItemId = item.getItemId(); | ||||
| //        if (item.getItemId() == R.id.item_log) { | ||||
| //            WinBollActivityManager.getInstance(this).startWinBollActivity(getApplicationContext(), LogActivity.class); | ||||
| //            WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(getApplicationContext(), LogActivity.class); | ||||
| //        } else  | ||||
|         if (nItemId == R.id.item_atoast) { | ||||
|             Toast.makeText(getApplication(), "item_testatoast", Toast.LENGTH_SHORT).show(); | ||||
|   | ||||
| @@ -0,0 +1 @@ | ||||
|  | ||||
|   | ||||
| @@ -24,7 +24,7 @@ android { | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.androiddemo" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 29 | ||||
|         targetSdkVersion 30 | ||||
|         versionCode 1 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
| @@ -67,6 +67,6 @@ dependencies { | ||||
|     // https://mvnrepository.com/artifact/com.android.support/recyclerview-v7 | ||||
|     api 'com.android.support:recyclerview-v7:28.0.0' | ||||
|      | ||||
|     api 'cc.winboll.studio:libapputils:15.2.2' | ||||
|     api 'cc.winboll.studio:libappbase:15.2.2' | ||||
|     api 'cc.winboll.studio:libapputils:15.8.5' | ||||
|     api 'cc.winboll.studio:libappbase:15.9.5' | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Thu Apr 03 03:17:18 GMT 2025 | ||||
| stageCount=0 | ||||
| #Sun Aug 31 05:11:26 CST 2025 | ||||
| stageCount=1 | ||||
| libraryProject= | ||||
| baseVersion=15.0 | ||||
| publishVersion=15.0.0 | ||||
| buildCount=21 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.0.1 | ||||
|   | ||||
| @@ -0,0 +1 @@ | ||||
|  | ||||
|   | ||||
| @@ -24,12 +24,12 @@ android { | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.androidxdemo" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 29 | ||||
|         targetSdkVersion 30 | ||||
|         versionCode 1 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.0" | ||||
|         versionName "15.1" | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
| @@ -67,7 +67,7 @@ dependencies { | ||||
|     //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0' | ||||
|     //api 'androidx.fragment:fragment:1.1.0' | ||||
|      | ||||
|     api 'cc.winboll.studio:libaes:15.2.6' | ||||
|     api 'cc.winboll.studio:libapputils:15.2.2' | ||||
|     api 'cc.winboll.studio:libappbase:15.2.2' | ||||
|     api 'cc.winboll.studio:libaes:15.9.3' | ||||
|     api 'cc.winboll.studio:libapputils:15.8.5' | ||||
|     api 'cc.winboll.studio:libappbase:15.9.5' | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Thu Apr 03 03:15:55 GMT 2025 | ||||
| stageCount=0 | ||||
| #Sun Aug 31 05:42:50 CST 2025 | ||||
| stageCount=2 | ||||
| libraryProject= | ||||
| baseVersion=15.0 | ||||
| publishVersion=15.0.0 | ||||
| buildCount=18 | ||||
| baseBetaVersion=15.0.1 | ||||
| baseVersion=15.1 | ||||
| publishVersion=15.1.1 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.1.2 | ||||
|   | ||||
| @@ -22,9 +22,9 @@ import android.widget.HorizontalScrollView; | ||||
| import android.widget.ScrollView; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import cc.winboll.studio.androidxdemo.R; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import com.hjq.toast.style.WhiteToastStyle; | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.Closeable; | ||||
| @@ -53,8 +53,8 @@ public class App extends GlobalApplication { | ||||
|         // 初始化 Toast 框架 | ||||
|         ToastUtils.init(this); | ||||
|         // 设置 Toast 布局样式 | ||||
|         ToastUtils.setView(R.layout.view_toast); | ||||
|         //ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         //ToastUtils.setView(R.layout.view_toast); | ||||
|         ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         ToastUtils.setGravity(Gravity.BOTTOM, 0, 200); | ||||
|          | ||||
|         //CrashHandler.getInstance().registerGlobal(this); | ||||
|   | ||||
| @@ -30,7 +30,7 @@ android { | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.7" | ||||
|         versionName "15.10" | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Tue Apr 29 14:47:16 HKT 2025 | ||||
| stageCount=7 | ||||
| #Mon Sep 22 06:01:08 HKT 2025 | ||||
| stageCount=8 | ||||
| libraryProject=libappbase | ||||
| baseVersion=15.7 | ||||
| publishVersion=15.7.6 | ||||
| baseVersion=15.10 | ||||
| publishVersion=15.10.7 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.7.7 | ||||
| baseBetaVersion=15.10.8 | ||||
|   | ||||
| @@ -2,7 +2,10 @@ | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|     <application | ||||
| 		tools:replace="android:icon,android:roundIcon" | ||||
|         android:icon="@drawable/ic_winboll_beta" | ||||
|         android:roundIcon="@drawable/ic_winboll_beta"> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|  | ||||
|   | ||||
| @@ -2,16 +2,19 @@ | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.appbase"> | ||||
|  | ||||
| 	 | ||||
| 	<!-- 网络权限 --> | ||||
| 	<uses-permission android:name="android.permission.INTERNET" /> | ||||
| 		 | ||||
|     <application | ||||
|         android:name=".App" | ||||
|         android:icon="@drawable/ic_miapp" | ||||
|         android:icon="@drawable/ic_winboll" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/MyAPPBaseTheme" | ||||
|         android:resizeableActivity="true" | ||||
|         android:process=":App"> | ||||
|  | ||||
|         <activity | ||||
| 		<activity | ||||
|             android:name=".MainActivity" | ||||
|             android:label="@string/app_name" | ||||
|             android:exported="true" | ||||
| @@ -24,105 +27,18 @@ | ||||
|  | ||||
|                 <category android:name="android.intent.category.LAUNCHER"/> | ||||
|  | ||||
|                 <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activities.NewActivity" | ||||
|             android:label="NewActivity" | ||||
|             android:exported="true" | ||||
|             android:resizeableActivity="true" | ||||
|             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/> | ||||
|  | ||||
|         <activity android:name=".activities.New2Activity" | ||||
|             android:label="New2Activity" | ||||
|             android:exported="true" | ||||
|             android:resizeableActivity="true" | ||||
|             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/> | ||||
|  | ||||
|         <service | ||||
|             android:name=".MyTileService" | ||||
|             android:exported="true" | ||||
|             android:label="@string/tileservice_name" | ||||
|             android:icon="@drawable/ic_launcher" | ||||
|             android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.service.quicksettings.action.QS_TILE"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </service> | ||||
|  | ||||
|         <service | ||||
|             android:name=".services.MainService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <service | ||||
|             android:name="cc.winboll.studio.appbase.services.TestDemoBindService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <service | ||||
|             android:name="cc.winboll.studio.appbase.services.TestDemoService" | ||||
|             android:exported="true"/> | ||||
|  | ||||
|         <service android:name=".services.AssistantService"/> | ||||
|  | ||||
|         <receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.receivers.MainReceiver"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".widgets.APPNewsWidget" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_WAKEUP_SERVICE"/> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.widgets.APPNewsWidget.ACTION_RELOAD_REPORT"/> | ||||
|  | ||||
|                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|             <meta-data | ||||
|                 android:name="android.appwidget.provider" | ||||
|                 android:resource="@xml/widget_provider_info_sos"/> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver android:name=".receivers.APPNewsWidgetClickListener" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_PRE"/> | ||||
|  | ||||
|                 <action android:name="cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener.ACTION_NEXT"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
| 		 | ||||
|         <activity android:name=".GlobalApplication$CrashActivity"/> | ||||
| 		 | ||||
|         <meta-data | ||||
|             android:name="android.max_aspect" | ||||
|             android:value="4.0"/> | ||||
|  | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|   | ||||
| @@ -1,27 +1,19 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/01/05 09:54:42 | ||||
|  * @Describe APPbase 应用类 | ||||
|  */ | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import android.content.IntentFilter; | ||||
| import cc.winboll.studio.libappbase.sos.SOSCenterServiceReceiver; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
|  | ||||
| public class App extends GlobalApplication { | ||||
|  | ||||
|     public static final String TAG = "App"; | ||||
|      | ||||
|     SOSCenterServiceReceiver mSOSCenterServiceReceiver; | ||||
|      | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         mSOSCenterServiceReceiver = new SOSCenterServiceReceiver(); | ||||
|         IntentFilter intentFilter = new IntentFilter(); | ||||
|         intentFilter.addAction(SOS.ACTION_SOS); | ||||
|         registerReceiver(mSOSCenterServiceReceiver, intentFilter); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,44 +1,24 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| import android.app.Activity; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.Toast; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.activities.NewActivity; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
| import cc.winboll.studio.appbase.services.TestDemoBindService; | ||||
| import cc.winboll.studio.appbase.services.TestDemoService; | ||||
| import cc.winboll.studio.libappbase.CrashHandler; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.GlobalCrashActivity; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| import cc.winboll.studio.libappbase.widgets.StatusWidget; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import cc.winboll.studio.libappbase.LogActivity; | ||||
| import cc.winboll.studio.libappbase.ToastUtils; | ||||
|  | ||||
| public class MainActivity extends WinBoLLActivityBase implements IWinBoLLActivity { | ||||
| public class MainActivity extends Activity { | ||||
|  | ||||
|     public static final String TAG = "MainActivity"; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|     //LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
| @@ -48,136 +28,47 @@ public class MainActivity extends WinBoLLActivityBase implements IWinBoLLActivit | ||||
|  | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
|         setActionBar(mToolbar); | ||||
|  | ||||
|         CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1); | ||||
|         cbIsDebugMode.setChecked(GlobalApplication.isDebuging()); | ||||
|         //mLogView = findViewById(R.id.activitymainLogView1); | ||||
|  | ||||
| //        if (GlobalApplication.isDebuging()) { | ||||
| //            mLogView.start();  | ||||
| //            ToastUtils.show("LogView start."); | ||||
| //        } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_appbase, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
| 		switch (item.getItemId()) { | ||||
| 			case R.id.item_home : { | ||||
| 					openWebsiteInBrowser(this); | ||||
| 				} | ||||
| 		} | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         Intent intentAPPWidget = new Intent(this, StatusWidget.class); | ||||
|         intentAPPWidget.setAction(StatusWidget.ACTION_STATUS_UPDATE); | ||||
|         sendBroadcast(intentAPPWidget); | ||||
|     public void onCrashTest(View view) { | ||||
| 		for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) { | ||||
| 			getString(i); | ||||
| 		} | ||||
|     } | ||||
|  | ||||
| 	public void onSwitchDebugMode(View view) { | ||||
|         boolean isDebuging = ((CheckBox)view).isChecked(); | ||||
|         GlobalApplication.setIsDebuging(isDebuging); | ||||
|         GlobalApplication.saveDebugStatus(); | ||||
|     } | ||||
|     | ||||
|     public void onPreviewGlobalCrashActivity(View view) { | ||||
|         Intent intent = new Intent(this, GlobalCrashActivity.class); | ||||
|         intent.putExtra(CrashHandler.EXTRA_CRASH_INFO, "Demo log..."); | ||||
|         startActivity(intent); | ||||
|     public void onLogTest(View view) { | ||||
|         LogActivity.startLogActivity(this); | ||||
|     } | ||||
|  | ||||
|     public void onStartCenter(View view) { | ||||
|         MainService.startMainService(this); | ||||
|     } | ||||
|  | ||||
|     public void onStopCenter(View view) { | ||||
|         MainService.stopMainService(this); | ||||
|     } | ||||
|  | ||||
|     public void onTestStopMainServiceWithoutSettingEnable(View view) { | ||||
|         LogUtils.d(TAG, "onTestStopMainServiceWithoutSettingEnable"); | ||||
|         stopService(new Intent(this, MainService.class)); | ||||
|     } | ||||
|  | ||||
|     public void onTestUseComponentStartService(View view) { | ||||
|         LogUtils.d(TAG, "onTestUseComponentStartService"); | ||||
|  | ||||
|         // 目标服务的包名和类名 | ||||
|         String packageName = this.getPackageName(); | ||||
|         String serviceClassName = TestDemoService.class.getName(); | ||||
|  | ||||
|         // 构建Intent | ||||
|         Intent intentService = new Intent(); | ||||
|         intentService.setComponent(new ComponentName(packageName, serviceClassName)); | ||||
|  | ||||
|         startService(intentService); | ||||
|     } | ||||
|  | ||||
|     public void onTestDemoServiceSOS(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         stopService(intent); | ||||
|         if (App.isDebuging()) { | ||||
|             SOS.sosToAppBaseBeta(this, TestDemoService.class.getName()); | ||||
|         } else { | ||||
|             SOS.sosToAppBase(this, TestDemoService.class.getName()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onSartTestDemoService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         intent.setAction(TestDemoService.ACTION_ENABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|     } | ||||
|      | ||||
|      | ||||
|  | ||||
|     public void onStopTestDemoService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         intent.setAction(TestDemoService.ACTION_DISABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|         Intent intentStop = new Intent(this, TestDemoService.class); | ||||
|         stopService(intentStop); | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoServiceNoSettings(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoService.class); | ||||
|         stopService(intent); | ||||
|     } | ||||
|  | ||||
|     public void onSartTestDemoBindService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoBindService.class); | ||||
|         intent.setAction(TestDemoBindService.ACTION_ENABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoBindService(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoBindService.class); | ||||
|         intent.setAction(TestDemoBindService.ACTION_DISABLE); | ||||
|         startService(intent); | ||||
|  | ||||
|         Intent intentStop = new Intent(this, TestDemoBindService.class); | ||||
|         stopService(intentStop); | ||||
|     } | ||||
|  | ||||
|     public void onStopTestDemoBindServiceNoSettings(View view) { | ||||
|         Intent intent = new Intent(this, TestDemoBindService.class); | ||||
|         stopService(intent); | ||||
|     } | ||||
|  | ||||
|     public void onTestOpenNewActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, NewActivity.class); | ||||
|     } | ||||
|  | ||||
|      | ||||
| 	/** | ||||
| 	 * 唤起默认浏览器打开指定网站 | ||||
| 	 * @param context 上下文(如 Activity.this) | ||||
| 	 */ | ||||
| 	public void openWebsiteInBrowser(Context context) { | ||||
| 		// 目标网站地址 | ||||
| 		String url = "https://www.winboll.cc"; | ||||
| 		// 构建打开浏览器的意图 | ||||
| 		Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); | ||||
| 		// 设置标志:避免创建新的任务栈(可选,按需求调整) | ||||
| 		intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
| 		context.startActivity(intent); | ||||
| 		 | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,79 +0,0 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/13 19:30:10 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.service.quicksettings.Tile; | ||||
| import android.service.quicksettings.TileService; | ||||
| import cc.winboll.studio.appbase.models.MainServiceBean; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
|  | ||||
| public class MyTileService extends TileService { | ||||
|     public static final String TAG = "MyTileService"; | ||||
|  | ||||
|     volatile static MyTileService _MyTileService; | ||||
|  | ||||
|     @Override | ||||
|     public void onStartListening() { | ||||
|         super.onStartListening(); | ||||
|         _MyTileService = this; | ||||
|         Tile tile = getQsTile(); | ||||
|         MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         if (bean != null && bean.isEnable()) { | ||||
|             //MainService.startMainService(context); | ||||
|             tile.setState(Tile.STATE_ACTIVE); | ||||
|             tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud)); | ||||
|         } else { | ||||
|             //MainService.stopMainService(context); | ||||
|             tile.setState(Tile.STATE_INACTIVE); | ||||
|             tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline)); | ||||
|         } | ||||
|         tile.updateTile(); | ||||
| //        Tile tile = getQsTile(); | ||||
| //        tile.setState(Tile.STATE_INACTIVE); | ||||
| //        tile.setLabel(getString(R.string.tileservice_name)); | ||||
| //        tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_cloud_outline)); | ||||
| //        tile.updateTile(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onClick() { | ||||
|         super.onClick(); | ||||
|         Tile tile = getQsTile(); | ||||
|         MainServiceBean bean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new MainServiceBean(); | ||||
|         } | ||||
|  | ||||
|         if (tile.getState() == Tile.STATE_ACTIVE) { | ||||
|             bean.setIsEnable(false); | ||||
|             MainServiceBean.saveBean(this, bean); | ||||
|             MainService.stopMainService(this); | ||||
|         } else if (tile.getState() == Tile.STATE_INACTIVE) { | ||||
|             bean.setIsEnable(true); | ||||
|             MainServiceBean.saveBean(this, bean); | ||||
|             MainService.startMainService(this); | ||||
|         } | ||||
|         updateServiceIconStatus(this); | ||||
|     } | ||||
|  | ||||
|     public static void updateServiceIconStatus(Context context) { | ||||
|         if (_MyTileService == null) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Tile tile = _MyTileService.getQsTile(); | ||||
|         MainServiceBean bean = MainServiceBean.loadBean(context, MainServiceBean.class); | ||||
|         if (bean != null && bean.isEnable()) { | ||||
|             tile.setState(Tile.STATE_ACTIVE); | ||||
|             tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud)); | ||||
|         } else { | ||||
|             tile.setState(Tile.STATE_INACTIVE); | ||||
|             tile.setIcon(android.graphics.drawable.Icon.createWithResource(context, R.drawable.ic_cloud_outline)); | ||||
|         } | ||||
|         tile.updateTile(); | ||||
|     } | ||||
| } | ||||
| @@ -1,81 +0,0 @@ | ||||
| package cc.winboll.studio.appbase; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/28 15:34:16 | ||||
|  * @Describe 应用活动窗口基类 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.os.PersistableBundle; | ||||
| import android.view.MenuItem; | ||||
| import cc.winboll.studio.appbase.App; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.dialogs.YesNoAlertDialog; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBoLLActivityManager; | ||||
|  | ||||
| public class WinBoLLActivityBase extends Activity implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "WinBoLLActivityBase"; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     WinBoLLActivityManager getWinBoLLActivityManager() { | ||||
|         return WinBoLLActivityManager.getInstance(GlobalApplication.getInstance()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         getWinBoLLActivityManager().add(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) { | ||||
|         super.onPostCreate(savedInstanceState, persistentState); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         if (item.getItemId() == cc.winboll.studio.appbase.R.id.item_log) { | ||||
|             GlobalApplication.getWinBoLLActivityManager().startLogActivity(this); | ||||
|             return true; | ||||
|         } else if(item.getItemId() == cc.winboll.studio.appbase.R.id.item_minimal) { | ||||
|             //moveTaskToBack(true); | ||||
|             exit(); | ||||
|         } | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     void exit() { | ||||
|         YesNoAlertDialog.show(this, "Exit " + getString(R.string.app_name), "Close all activity and exit?", new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|  | ||||
|                 @Override | ||||
|                 public void onYes() { | ||||
|                     App.getWinBoLLActivityManager().finishAll(); | ||||
|                 } | ||||
|  | ||||
|                 @Override | ||||
|                 public void onNo() { | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         getWinBoLLActivityManager().registeRemove(this); | ||||
|     } | ||||
| } | ||||
| @@ -1,83 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.activities; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/25 11:46:40 | ||||
|  * @Describe 测试窗口2 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.WinBoLLActivityBase; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
|  | ||||
| public class New2Activity extends WinBoLLActivityBase implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "New2Activity"; | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|     //LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_new2); | ||||
|  | ||||
| //        mLogView = findViewById(R.id.logview); | ||||
| //        mLogView.start(); | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
|         setActionBar(mToolbar); | ||||
|          | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         //mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onCloseThisActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().finish(this); | ||||
|     } | ||||
|  | ||||
|     public void onCloseAllActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().finishAll(); | ||||
|     } | ||||
|  | ||||
|     public void onNewActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, NewActivity.class); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_appbase, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         if (item.getItemId() == cc.winboll.studio.appbase.R.id.item_log) { | ||||
|             GlobalApplication.getWinBoLLActivityManager().startLogActivity(this); | ||||
|             return true; | ||||
|         } | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| } | ||||
| @@ -1,81 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.activities; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/25 05:04:22 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.WinBoLLActivityBase; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; | ||||
|  | ||||
| public class NewActivity extends WinBoLLActivityBase implements IWinBoLLActivity { | ||||
|  | ||||
|     public static final String TAG = "NewActivity"; | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|     //LogView mLogView; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_new); | ||||
| //        mLogView = findViewById(R.id.logview); | ||||
| //        mLogView.start(); | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
|         setActionBar(mToolbar); | ||||
|          | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         //mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     public void onCloseThisActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().finish(this); | ||||
|     } | ||||
|  | ||||
|     public void onCloseAllActivity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().finishAll(); | ||||
|     } | ||||
|  | ||||
|     public void onNew2Activity(View view) { | ||||
|         GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, New2Activity.class); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_appbase, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         if (item.getItemId() == cc.winboll.studio.appbase.R.id.item_log) { | ||||
|             GlobalApplication.getWinBoLLActivityManager().startLogActivity(this); | ||||
|             return true; | ||||
|         } | ||||
|         // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。 | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| } | ||||
| @@ -1,38 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.handlers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/14 03:51:40 | ||||
|  */ | ||||
| import android.os.Handler; | ||||
| import android.os.Message; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
| import java.lang.ref.WeakReference; | ||||
|  | ||||
| public class MainServiceHandler extends Handler { | ||||
|     public static final String TAG = "MainServiceHandler"; | ||||
|  | ||||
|     public static final int MSG_REMINDTHREAD = 0; | ||||
|  | ||||
|     WeakReference<MainService> serviceWeakReference; | ||||
|     public MainServiceHandler(MainService service) { | ||||
|         serviceWeakReference = new WeakReference<MainService>(service); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void handleMessage(Message msg) { | ||||
|         switch (msg.what) { | ||||
|             case MSG_REMINDTHREAD: // 处理下载完成消息,更新UI | ||||
|                 { | ||||
|                     // 显示提醒消息 | ||||
|                     // | ||||
|                     //LogUtils.d(TAG, "显示提醒消息"); | ||||
|                     MainService mainService = serviceWeakReference.get(); | ||||
|                     if (mainService != null) { | ||||
|                         mainService.appenMessage((String)msg.obj); | ||||
|                     } | ||||
|                     break; | ||||
|                 } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,67 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/07 12:47:22 | ||||
|  * @Describe TestServiceBean | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class TestDemoBindServiceBean extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "TestServiceBean"; | ||||
|  | ||||
|     boolean isEnable; | ||||
|  | ||||
|     public TestDemoBindServiceBean() { | ||||
|         this.isEnable = false; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnable(boolean isEnable) { | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return isEnable; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return TestDemoBindServiceBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("isEnable").value(isEnable()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("isEnable")) { | ||||
|                 setIsEnable(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,72 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/17 10:05:09 | ||||
|  * @Describe APPSOSReportBean | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class WinBoLLNewsBean extends BaseBean { | ||||
|      | ||||
|     public static final String TAG = "WinBoLLNewsBean"; | ||||
|      | ||||
|     protected String message; | ||||
|      | ||||
|     public WinBoLLNewsBean() { | ||||
|         this.message = ""; | ||||
|     } | ||||
|  | ||||
|     public WinBoLLNewsBean(String message) { | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public void setMessage(String message) { | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public String getMessage() { | ||||
|         return message; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return WinBoLLNewsBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("message").value(getMessage()); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("message")) { | ||||
|                 setMessage(jsonReader.nextString()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
| } | ||||
| @@ -1,36 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.receivers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/24 07:11:44 | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import cc.winboll.studio.appbase.widgets.APPNewsWidget; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| public class APPNewsWidgetClickListener extends BroadcastReceiver { | ||||
|  | ||||
|     public static final String TAG = "APPNewsWidgetClickListener"; | ||||
|     public static final String ACTION_PRE = APPNewsWidgetClickListener.class.getName() + ".ACTION_PRE"; | ||||
|     public static final String ACTION_NEXT = APPNewsWidgetClickListener.class.getName() + ".ACTION_NEXT"; | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String action = intent.getAction(); | ||||
|         if (action == null) { | ||||
|             LogUtils.d(TAG, String.format("action %s", action)); | ||||
|             return; | ||||
|         } | ||||
|         if (action.equals(ACTION_PRE)) { | ||||
|             LogUtils.d(TAG, "ACTION_PRE"); | ||||
|             APPNewsWidget.prePage(context); | ||||
|         } else if (action.equals(ACTION_NEXT)) { | ||||
|             LogUtils.d(TAG, "ACTION_NEXT"); | ||||
|             APPNewsWidget.nextPage(context); | ||||
|         } else { | ||||
|             LogUtils.d(TAG, String.format("action %s", action)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,117 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.receivers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/13 06:58:04 | ||||
|  * @Describe 主要广播接收器 | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.IntentFilter; | ||||
| import cc.winboll.studio.appbase.models.WinBoLLNewsBean; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
| import cc.winboll.studio.appbase.widgets.APPNewsWidget; | ||||
| import cc.winboll.studio.libappbase.AppUtils; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.sos.APPModel; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
| import cc.winboll.studio.libappbase.sos.SOSObject; | ||||
| import cc.winboll.studio.libappbase.sos.WinBoLL; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| import java.io.IOException; | ||||
| import java.lang.ref.WeakReference; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.Date; | ||||
|  | ||||
| public class MainReceiver extends BroadcastReceiver { | ||||
|  | ||||
|     public static final String TAG = "MainReceiver"; | ||||
|  | ||||
|     public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; | ||||
|  | ||||
|     WeakReference<MainService> mwrService; | ||||
|  | ||||
|     public MainReceiver(MainService service) { | ||||
|         mwrService = new WeakReference<MainService>(service); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String szAction = intent.getAction(); | ||||
|         if (szAction.equals(ACTION_BOOT_COMPLETED)) { | ||||
|             ToastUtils.show("ACTION_BOOT_COMPLETED"); | ||||
|         } else if (szAction.equals(WinBoLL.ACTION_BIND)) { | ||||
|             LogUtils.d(TAG, "ACTION_BIND"); | ||||
|             LogUtils.d(TAG, String.format("context.getPackageName() %s", context.getPackageName())); | ||||
|             LogUtils.d(TAG, String.format("intent.getAction() %s", intent.getAction())); | ||||
|             String szAPPModel = intent.getStringExtra(WinBoLL.EXTRA_APPMODEL); | ||||
|             LogUtils.d(TAG, String.format("szAPPModel %s", szAPPModel)); | ||||
|             if (szAPPModel != null && !szAPPModel.equals("")) { | ||||
|                 try { | ||||
|                     APPModel bean = APPModel.parseStringToBean(szAPPModel, APPModel.class); | ||||
|                     if (bean != null) { | ||||
|                         String szAppPackageName = bean.getAppPackageName(); | ||||
|                         LogUtils.d(TAG, String.format("szAppPackageName %s", szAppPackageName)); | ||||
|                         String szAppMainServiveName = bean.getAppMainServiveName(); | ||||
|                         LogUtils.d(TAG, String.format("szAppMainServiveName %s", szAppMainServiveName)); | ||||
|                         mwrService.get().bindAPPModelConnection(bean); | ||||
|                     } | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|         } else if (intent.getAction().equals(SOS.ACTION_SOS)) { | ||||
|             LogUtils.d(TAG, "ACTION_SOS"); | ||||
|             String sos = intent.getStringExtra(SOS.EXTRA_OBJECT); | ||||
|             LogUtils.d(TAG, String.format("SOS %s", sos)); | ||||
|             if (sos != null && !sos.equals("")) { | ||||
|                 SOSObject bean = SOS.parseSOSObject(sos); | ||||
|                 if (bean != null) { | ||||
|                     String szObjectPackageName = bean.getObjectPackageName(); | ||||
|                     LogUtils.d(TAG, String.format("szObjectPackageName %s", szObjectPackageName)); | ||||
|                     String szObjectServiveName = bean.getObjectServiveName(); | ||||
|                     LogUtils.d(TAG, String.format("szObjectServiveName %s", szObjectServiveName)); | ||||
|  | ||||
|                     Intent intentService = new Intent(); | ||||
|                     intentService.setComponent(new ComponentName(szObjectPackageName, szObjectServiveName)); | ||||
|                     context.startService(intentService); | ||||
|  | ||||
|                     String appName = AppUtils.getAppNameByPackageName(context, szObjectPackageName); | ||||
|                     LogUtils.d(TAG, String.format("appName %s", appName)); | ||||
|                     WinBoLLNewsBean appWinBoLLNewsBean = new WinBoLLNewsBean(appName); | ||||
|                     SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); | ||||
|                     String currentTime = sdf.format(new Date()); | ||||
|                     StringBuilder sbLine = new StringBuilder(); | ||||
|                     sbLine.append("["); | ||||
|                     sbLine.append(currentTime); | ||||
|                     sbLine.append("] Power to "); | ||||
|                     sbLine.append(appName); | ||||
|                     appWinBoLLNewsBean.setMessage(sbLine.toString()); | ||||
|  | ||||
|                     APPNewsWidget.addWinBoLLNewsBean(context, appWinBoLLNewsBean); | ||||
|  | ||||
|                     Intent intentWidget = new Intent(context, APPNewsWidget.class); | ||||
|                     intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT); | ||||
|                     context.sendBroadcast(intentWidget); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|             } | ||||
|         } else { | ||||
|             ToastUtils.show(szAction); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 注册 Receiver | ||||
|     // | ||||
|     public void registerAction(MainService service) { | ||||
|         IntentFilter filter=new IntentFilter(); | ||||
|         filter.addAction(ACTION_BOOT_COMPLETED); | ||||
|         filter.addAction(SOS.ACTION_SOS); | ||||
|         filter.addAction(WinBoLL.ACTION_BIND); | ||||
|         //filter.addAction(Intent.ACTION_BATTERY_CHANGED); | ||||
|         service.registerReceiver(this, filter); | ||||
|     } | ||||
| } | ||||
| @@ -1,138 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/14 03:38:31 | ||||
|  * @Describe 守护进程服务 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.appbase.models.MainServiceBean; | ||||
| import cc.winboll.studio.appbase.services.AssistantService; | ||||
| import cc.winboll.studio.appbase.services.MainService; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import android.os.Binder; | ||||
|  | ||||
| public class AssistantService extends Service { | ||||
|  | ||||
|     public static final String TAG = "AssistantService"; | ||||
|  | ||||
|     MainServiceBean mMainServiceBean; | ||||
|     MyServiceConnection mMyServiceConnection; | ||||
|     MainService mMainService; | ||||
|     boolean isBound = false; | ||||
|     volatile boolean isThreadAlive = false; | ||||
|  | ||||
|     public synchronized void setIsThreadAlive(boolean isThreadAlive) { | ||||
|         LogUtils.d(TAG, "setIsThreadAlive(...)"); | ||||
|         LogUtils.d(TAG, String.format("isThreadAlive %s", isThreadAlive)); | ||||
|         this.isThreadAlive = isThreadAlive; | ||||
|     } | ||||
|  | ||||
|     public boolean isThreadAlive() { | ||||
|         return isThreadAlive; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return new MyBinder(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         LogUtils.d(TAG, "onCreate"); | ||||
|         super.onCreate(); | ||||
|  | ||||
|         //mMyBinder = new MyBinder(); | ||||
|         if (mMyServiceConnection == null) { | ||||
|             mMyServiceConnection = new MyServiceConnection(); | ||||
|         } | ||||
|         // 设置运行参数 | ||||
|         setIsThreadAlive(false); | ||||
|         assistantService(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "call onStartCommand(...)"); | ||||
|         assistantService(); | ||||
|         return START_STICKY; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         //LogUtils.d(TAG, "onDestroy"); | ||||
|         setIsThreadAlive(false); | ||||
|         // 解除绑定 | ||||
|         if (isBound) { | ||||
|             unbindService(mMyServiceConnection); | ||||
|             isBound = false; | ||||
|         } | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
|     // 运行服务内容 | ||||
|     // | ||||
|     void assistantService() { | ||||
|         LogUtils.d(TAG, "assistantService()"); | ||||
|         mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         LogUtils.d(TAG, String.format("mMainServiceBean.isEnable() %s", mMainServiceBean.isEnable())); | ||||
|         if (mMainServiceBean.isEnable()) { | ||||
|             LogUtils.d(TAG, String.format("mIsThreadAlive %s", isThreadAlive())); | ||||
|             if (isThreadAlive() == false) { | ||||
|                 // 设置运行状态 | ||||
|                 setIsThreadAlive(true); | ||||
|                 // 唤醒和绑定主进程 | ||||
|                 wakeupAndBindMain(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 唤醒和绑定主进程 | ||||
|     // | ||||
|     void wakeupAndBindMain() { | ||||
|         LogUtils.d(TAG, "wakeupAndBindMain()"); | ||||
|         // 绑定服务的Intent | ||||
|         Intent intent = new Intent(this, MainService.class); | ||||
|         startService(new Intent(this, MainService.class)); | ||||
|         bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|      | ||||
| //        startService(new Intent(this, MainService.class)); | ||||
| //        bindService(new Intent(AssistantService.this, MainService.class), mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|     } | ||||
|  | ||||
|     // 主进程与守护进程连接时需要用到此类 | ||||
|     // | ||||
|     class MyServiceConnection implements ServiceConnection { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             LogUtils.d(TAG, "onServiceConnected(...)"); | ||||
|             MainService.MyBinder binder = (MainService.MyBinder) service; | ||||
|             mMainService = binder.getService(); | ||||
|             isBound = true; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             LogUtils.d(TAG, "onServiceDisconnected(...)"); | ||||
|             mMainServiceBean = MainServiceBean.loadBean(AssistantService.this, MainServiceBean.class); | ||||
|             if (mMainServiceBean.isEnable()) { | ||||
|                 wakeupAndBindMain(); | ||||
|             } | ||||
|             isBound = false; | ||||
|             mMainService = null; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     // 用于返回服务实例的Binder | ||||
|     public class MyBinder extends Binder { | ||||
|         AssistantService getService() { | ||||
|             LogUtils.d(TAG, "AssistantService MyBinder getService()"); | ||||
|             return AssistantService.this; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,316 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/13 06:56:41 | ||||
|  * @Describe 拨号主服务 | ||||
|  * 参考: | ||||
|  * 进程保活-双进程守护的正确姿势 | ||||
|  * https://blog.csdn.net/sinat_35159441/article/details/75267380 | ||||
|  * Android Service之onStartCommand方法研究 | ||||
|  * https://blog.csdn.net/cyp331203/article/details/38920491 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.Binder; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.appbase.MyTileService; | ||||
| import cc.winboll.studio.appbase.models.MainServiceBean; | ||||
| import cc.winboll.studio.appbase.handlers.MainServiceHandler; | ||||
| import cc.winboll.studio.appbase.receivers.MainReceiver; | ||||
| import cc.winboll.studio.appbase.services.AssistantService; | ||||
| import cc.winboll.studio.appbase.threads.MainServiceThread; | ||||
| import cc.winboll.studio.appbase.widgets.APPNewsWidget; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.util.ArrayList; | ||||
| import cc.winboll.studio.libappbase.sos.APPModel; | ||||
|  | ||||
| public class MainService extends Service { | ||||
|  | ||||
|     public static final String TAG = "MainService"; | ||||
|  | ||||
|     public static final int MSG_UPDATE_STATUS = 0; | ||||
|  | ||||
|     static MainService _mControlCenterService; | ||||
|  | ||||
|     volatile boolean isServiceRunning; | ||||
|  | ||||
|     MainServiceBean mMainServiceBean; | ||||
|     MainServiceThread mMainServiceThread; | ||||
|     MainServiceHandler mMainServiceHandler; | ||||
|     MyServiceConnection mMyServiceConnection; | ||||
|     AssistantService mAssistantService; | ||||
|     boolean isBound = false; | ||||
|     MainReceiver mMainReceiver; | ||||
|     ArrayList<APPConnection> mAPPModelConnectionList; | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return new MyBinder(); | ||||
|     } | ||||
|  | ||||
|     public MainServiceThread getRemindThread() { | ||||
|         return mMainServiceThread; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         LogUtils.d(TAG, "onCreate()"); | ||||
|         mAPPModelConnectionList = new ArrayList<APPConnection>(); | ||||
|  | ||||
|         _mControlCenterService = MainService.this; | ||||
|         isServiceRunning = false; | ||||
|         mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|  | ||||
|         if (mMyServiceConnection == null) { | ||||
|             mMyServiceConnection = new MyServiceConnection(); | ||||
|         } | ||||
|         mMainServiceHandler = new MainServiceHandler(this); | ||||
|  | ||||
|         // 运行服务内容 | ||||
|         mainService(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "onStartCommand(...)"); | ||||
|         // 运行服务内容 | ||||
|         mainService(); | ||||
|         return (mMainServiceBean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|     // 运行服务内容 | ||||
|     // | ||||
|     void mainService() { | ||||
|         LogUtils.d(TAG, "mainService()"); | ||||
|         mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         if (mMainServiceBean.isEnable() && isServiceRunning == false) { | ||||
|             LogUtils.d(TAG, "mainService() start running"); | ||||
|             isServiceRunning = true; | ||||
|             // 唤醒守护进程 | ||||
|             wakeupAndBindAssistant(); | ||||
|  | ||||
|             if (mMainReceiver == null) { | ||||
|                 // 注册广播接收器 | ||||
|                 mMainReceiver = new MainReceiver(this); | ||||
|                 mMainReceiver.registerAction(this); | ||||
|             } | ||||
|  | ||||
|             // 启动小部件 | ||||
|             Intent intentTimeWidget = new Intent(this, APPNewsWidget.class); | ||||
|             intentTimeWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT); | ||||
|             this.sendBroadcast(intentTimeWidget); | ||||
|  | ||||
|             startMainServiceThread(); | ||||
|  | ||||
|             MyTileService.updateServiceIconStatus(this); | ||||
|  | ||||
|             LogUtils.i(TAG, "Main Service Is Start."); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 唤醒和绑定守护进程 | ||||
|     // | ||||
|     void wakeupAndBindAssistant() { | ||||
|         LogUtils.d(TAG, "wakeupAndBindAssistant()"); | ||||
|  | ||||
|         Intent intent = new Intent(this, AssistantService.class); | ||||
|         startService(intent); | ||||
|         // 绑定服务的Intent | ||||
|         bindService(intent, mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|     } | ||||
|  | ||||
|     // 开启提醒铃声线程 | ||||
|     // | ||||
|     public void startMainServiceThread() { | ||||
|         LogUtils.d(TAG, "startMainServiceThread"); | ||||
|         if (mMainServiceThread == null) { | ||||
|             mMainServiceThread = new MainServiceThread(this, mMainServiceHandler); | ||||
|             LogUtils.d(TAG, "new MainServiceThread"); | ||||
|         } else { | ||||
|             if (mMainServiceThread.isExist() == true) { | ||||
|                 mMainServiceThread = new MainServiceThread(this, mMainServiceHandler); | ||||
|                 LogUtils.d(TAG, "renew MainServiceThread"); | ||||
|             } else { | ||||
|                 // 提醒进程正在进行中就更新状态后退出 | ||||
|                 LogUtils.d(TAG, "A mMainServiceThread running."); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         mMainServiceThread.start(); | ||||
|     } | ||||
|  | ||||
|     public void stopRemindThread() { | ||||
|         if (mMainServiceThread != null) { | ||||
|             mMainServiceThread.setIsExist(true); | ||||
|             mMainServiceThread = null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         //LogUtils.d(TAG, "onDestroy"); | ||||
|         mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); | ||||
|         if (mMainServiceBean.isEnable() == false) { | ||||
|             // 设置运行状态 | ||||
|             isServiceRunning = false;// 解除绑定 | ||||
|             if (isBound) { | ||||
|                 unbindService(mMyServiceConnection); | ||||
|                 isBound = false; | ||||
|             } | ||||
|             // 停止守护进程 | ||||
|             Intent intent = new Intent(this, AssistantService.class); | ||||
|             stopService(intent); | ||||
|             // 停止Receiver | ||||
|             if (mMainReceiver != null) { | ||||
|                 unregisterReceiver(mMainReceiver); | ||||
|                 mMainReceiver = null; | ||||
|             } | ||||
|             // 停止前台通知栏 | ||||
|             stopForeground(true); | ||||
|             // 停止消息提醒进程 | ||||
|             stopRemindThread(); | ||||
|  | ||||
|             MyTileService.updateServiceIconStatus(this); | ||||
|  | ||||
|             super.onDestroy(); | ||||
|             //LogUtils.d(TAG, "onDestroy done"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void bindAPPModelConnection(APPModel bean) { | ||||
|         LogUtils.d(TAG, "bindAPPModelConnection(...)"); | ||||
|         // 清理旧的绑定链接 | ||||
|         for (int i = mAPPModelConnectionList.size() - 1; i > -1; i--) { | ||||
|             APPConnection item = mAPPModelConnectionList.get(i); | ||||
|             if (item.isBindToAPP(bean)) { | ||||
|                 LogUtils.d(TAG, "Bind Servive exist."); | ||||
|                 unbindService(item); | ||||
|                 mAPPModelConnectionList.remove(i); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // 绑定服务 | ||||
|         APPConnection appConnection = new APPConnection(); | ||||
|         Intent intentService = new Intent(); | ||||
|         intentService.setComponent(new ComponentName(bean.getAppPackageName(), bean.getAppMainServiveName())); | ||||
|         bindService(intentService, appConnection, Context.BIND_IMPORTANT); | ||||
|         mAPPModelConnectionList.add(appConnection); | ||||
|          | ||||
|         Intent intentWidget = new Intent(this, APPNewsWidget.class); | ||||
|         intentWidget.setAction(APPNewsWidget.ACTION_WAKEUP_SERVICE); | ||||
|         APPModel appSOSBean = new APPModel(bean.getAppPackageName(), bean.getAppMainServiveName()); | ||||
|         intentWidget.putExtra("APPSOSBean", appSOSBean.toString()); | ||||
|         sendBroadcast(intentWidget); | ||||
|     } | ||||
|  | ||||
|     public class APPConnection implements ServiceConnection { | ||||
|  | ||||
|         ComponentName mComponentName; | ||||
|  | ||||
|         boolean isBindToAPP(APPModel bean) { | ||||
|             return mComponentName != null | ||||
|                 && mComponentName.getClassName().equals(bean.getAppMainServiveName()) | ||||
|                 && mComponentName.getPackageName().equals(bean.getAppPackageName()); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             LogUtils.d(TAG, "onServiceConnected(...)"); | ||||
|             mComponentName = name; | ||||
|             LogUtils.d(TAG, String.format("onServiceConnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName())); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             LogUtils.d(TAG, "onServiceDisconnected(...)"); | ||||
|             LogUtils.d(TAG, String.format("onServiceDisconnected : \ngetClassName %s\ngetPackageName %s", name.getClassName(), name.getPackageName())); | ||||
|  | ||||
|             // 尝试无参数启动一下服务 | ||||
|             String appPackage = mComponentName.getPackageName(); | ||||
|             LogUtils.d(TAG, String.format("appPackage %s", appPackage)); | ||||
|             String appMainServiceClassName = mComponentName.getClassName(); | ||||
|             LogUtils.d(TAG, String.format("appMainServiceClassName %s", appMainServiceClassName)); | ||||
|  | ||||
|             Intent intentService = new Intent(); | ||||
|             intentService.setComponent(new ComponentName(appPackage, appMainServiceClassName)); | ||||
|             startService(intentService); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     // 主进程与守护进程连接时需要用到此类 | ||||
|     // | ||||
|     private class MyServiceConnection implements ServiceConnection { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             LogUtils.d(TAG, "onServiceConnected(...)"); | ||||
|             AssistantService.MyBinder binder = (AssistantService.MyBinder) service; | ||||
|             mAssistantService = binder.getService(); | ||||
|             isBound = true; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             LogUtils.d(TAG, "onServiceDisconnected(...)"); | ||||
|  | ||||
|             if (mMainServiceBean.isEnable()) { | ||||
|                 // 唤醒守护进程 | ||||
|                 wakeupAndBindAssistant(); | ||||
|             } | ||||
|             isBound = false; | ||||
|             mAssistantService = null; | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // 用于返回服务实例的Binder | ||||
|     public class MyBinder extends Binder { | ||||
|         MainService getService() { | ||||
|             LogUtils.d(TAG, "MainService MyBinder getService()"); | ||||
|             return MainService.this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| //    // | ||||
| //    // 启动服务 | ||||
| //    // | ||||
| //    public static void startControlCenterService(Context context) { | ||||
| //        Intent intent = new Intent(context, MainService.class); | ||||
| //        context.startForegroundService(intent); | ||||
| //    } | ||||
| // | ||||
| //    // | ||||
| //    // 停止服务 | ||||
| //    // | ||||
| //    public static void stopControlCenterService(Context context) { | ||||
| //        Intent intent = new Intent(context, MainService.class); | ||||
| //        context.stopService(intent); | ||||
| //    } | ||||
|  | ||||
|     public void appenMessage(String message) { | ||||
|         LogUtils.d(TAG, String.format("Message : %s", message)); | ||||
|     } | ||||
|  | ||||
|     public static void stopMainService(Context context) { | ||||
|         LogUtils.d(TAG, "stopMainService"); | ||||
|         MainServiceBean bean = new MainServiceBean(); | ||||
|         bean.setIsEnable(false); | ||||
|         MainServiceBean.saveBean(context, bean); | ||||
|         context.stopService(new Intent(context, MainService.class)); | ||||
|     } | ||||
|  | ||||
|     public static void startMainService(Context context) { | ||||
|         LogUtils.d(TAG, "startMainService"); | ||||
|         MainServiceBean bean = new MainServiceBean(); | ||||
|         bean.setIsEnable(true); | ||||
|         MainServiceBean.saveBean(context, bean); | ||||
|         context.startService(new Intent(context, MainService.class)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,178 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/07 12:45:49 | ||||
|  * @Describe 启动时申请绑定到APPBase主服务的服务示例 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Binder; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.appbase.models.TestDemoBindServiceBean; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.sos.WinBoLL; | ||||
| import cc.winboll.studio.appbase.App; | ||||
| import cc.winboll.studio.libappbase.sos.SOS; | ||||
|  | ||||
| public class TestDemoBindService extends Service { | ||||
|  | ||||
|     public static final String TAG = "TestDemoBindService"; | ||||
|  | ||||
|     public static final String ACTION_ENABLE = TestDemoBindService.class.getName() + ".ACTION_ENABLE"; | ||||
|     public static final String ACTION_DISABLE = TestDemoBindService.class.getName() + ".ACTION_DISABLE"; | ||||
|  | ||||
|     volatile static TestThread _TestThread; | ||||
|  | ||||
|     volatile static boolean _IsRunning; | ||||
|  | ||||
|     public synchronized static void setIsRunning(boolean isRunning) { | ||||
|         _IsRunning = isRunning; | ||||
|     } | ||||
|  | ||||
|     public static boolean isRunning() { | ||||
|         return _IsRunning; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return new MyBinder(); | ||||
|     } | ||||
|  | ||||
|     public class MyBinder extends Binder { | ||||
|         public TestDemoBindService getService() { | ||||
|             return TestDemoBindService.this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         LogUtils.d(TAG, "onCreate()"); | ||||
|  | ||||
|         run(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "onStartCommand(...)"); | ||||
|         TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoBindServiceBean(); | ||||
|         } | ||||
|  | ||||
|         if (intent.getAction() != null) { | ||||
|             if (intent.getAction().equals(ACTION_ENABLE)) { | ||||
|                 bean.setIsEnable(true); | ||||
|                 LogUtils.d(TAG, "setIsEnable(true);"); | ||||
|                 TestDemoBindServiceBean.saveBean(this, bean); | ||||
|             } else if (intent.getAction().equals(ACTION_DISABLE)) { | ||||
|                 bean.setIsEnable(false); | ||||
|                 LogUtils.d(TAG, "setIsEnable(false);"); | ||||
|                 TestDemoBindServiceBean.saveBean(this, bean); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         run(); | ||||
|  | ||||
|         return (bean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); | ||||
|         //return super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|     void run() { | ||||
|         LogUtils.d(TAG, "run()"); | ||||
|         TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoBindServiceBean(); | ||||
|             TestDemoBindServiceBean.saveBean(this, bean); | ||||
|         } | ||||
|         if (bean.isEnable()) { | ||||
|             LogUtils.d(TAG, "run() bean.isEnable()"); | ||||
|             TestThread.getInstance(this).start(); | ||||
|             LogUtils.d(TAG, "_TestThread.start()"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         LogUtils.d(TAG, "onDestroy()"); | ||||
|         TestDemoBindServiceBean bean = TestDemoBindServiceBean.loadBean(this, TestDemoBindServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoBindServiceBean(); | ||||
|         } | ||||
|  | ||||
|         TestThread.getInstance(this).setIsExit(true); | ||||
|          | ||||
|         // 预防 APPBase 应用重启绑定失效。 | ||||
|         // 所以退出时检查本服务是否配置启用,如果启用就发送一个 SOS 信号。 | ||||
|         // 这样 APPBase 就会用组件方式启动本服务。 | ||||
|         if (bean.isEnable()) { | ||||
|             if (App.isDebuging()) { | ||||
|                 SOS.sosToAppBaseBeta(this, TestDemoBindService.class.getName()); | ||||
|             } else { | ||||
|                 SOS.sosToAppBase(this, TestDemoBindService.class.getName()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         _IsRunning = false; | ||||
|     } | ||||
|  | ||||
|     static class TestThread extends Thread { | ||||
|  | ||||
|         volatile static TestThread _TestThread; | ||||
|         Context mContext; | ||||
|         volatile boolean isStarted = false; | ||||
|         volatile boolean isExit = false; | ||||
|  | ||||
|         TestThread(Context context) { | ||||
|             super(); | ||||
|             mContext = context; | ||||
|         } | ||||
|  | ||||
|         public static synchronized TestThread getInstance(Context context) { | ||||
|             if (_TestThread != null) { | ||||
|                 _TestThread.setIsExit(true); | ||||
|             } | ||||
|             _TestThread = new TestThread(context); | ||||
|  | ||||
|             return _TestThread; | ||||
|         } | ||||
|  | ||||
|         public synchronized void setIsExit(boolean isExit) { | ||||
|             this.isExit = isExit; | ||||
|         } | ||||
|  | ||||
|         public boolean isExit() { | ||||
|             return isExit; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|             if (isStarted == false) { | ||||
|                 isStarted = true; | ||||
|                 super.run(); | ||||
|                 LogUtils.d(TAG, "run() start"); | ||||
|                 if (App.isDebuging()) { | ||||
|                     WinBoLL.bindToAPPBaseBeta(mContext, TestDemoBindService.class.getName()); | ||||
|                 } else { | ||||
|                     WinBoLL.bindToAPPBase(mContext, TestDemoBindService.class.getName()); | ||||
|                 } | ||||
|  | ||||
|                 while (!isExit()) { | ||||
|                     LogUtils.d(TAG, "run()"); | ||||
|  | ||||
|                     try { | ||||
|                         Thread.sleep(1000); | ||||
|                     } catch (InterruptedException e) { | ||||
|                         LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 LogUtils.d(TAG, "run() exit"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,156 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/07 12:39:24 | ||||
|  * @Describe 普通服务示例 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Binder; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.appbase.models.TestDemoServiceBean; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.sos.WinBoLL; | ||||
|  | ||||
| public class TestDemoService extends Service { | ||||
|  | ||||
|     public static final String TAG = "TestDemoService"; | ||||
|  | ||||
|     public static final String ACTION_ENABLE = TestDemoService.class.getName() + ".ACTION_ENABLE"; | ||||
|     public static final String ACTION_DISABLE = TestDemoService.class.getName() + ".ACTION_DISABLE"; | ||||
|  | ||||
|     volatile static TestThread _TestThread; | ||||
|  | ||||
|     volatile static boolean _IsRunning; | ||||
|  | ||||
|     public synchronized static void setIsRunning(boolean isRunning) { | ||||
|         _IsRunning = isRunning; | ||||
|     } | ||||
|  | ||||
|     public static boolean isRunning() { | ||||
|         return _IsRunning; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return new MyBinder(); | ||||
|     } | ||||
|  | ||||
|     public class MyBinder extends Binder { | ||||
|         public TestDemoService getService() { | ||||
|             return TestDemoService.this; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         LogUtils.d(TAG, "onCreate()"); | ||||
|  | ||||
|  | ||||
|         run(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         LogUtils.d(TAG, "onStartCommand(...)"); | ||||
|         TestDemoServiceBean bean = TestDemoServiceBean.loadBean(this, TestDemoServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoServiceBean(); | ||||
|         } | ||||
|  | ||||
|         if (intent.getAction() != null) { | ||||
|             if (intent.getAction().equals(ACTION_ENABLE)) { | ||||
|                 bean.setIsEnable(true); | ||||
|                 LogUtils.d(TAG, "setIsEnable(true);"); | ||||
|                 TestDemoServiceBean.saveBean(this, bean); | ||||
|             } else if (intent.getAction().equals(ACTION_DISABLE)) { | ||||
|                 bean.setIsEnable(false); | ||||
|                 LogUtils.d(TAG, "setIsEnable(false);"); | ||||
|                 TestDemoServiceBean.saveBean(this, bean); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         run(); | ||||
|  | ||||
|         return (bean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); | ||||
|         //return super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|     void run() { | ||||
|         LogUtils.d(TAG, "run()"); | ||||
|         TestDemoServiceBean bean = TestDemoServiceBean.loadBean(this, TestDemoServiceBean.class); | ||||
|         if (bean == null) { | ||||
|             bean = new TestDemoServiceBean(); | ||||
|             TestDemoServiceBean.saveBean(this, bean); | ||||
|         } | ||||
|         if (bean.isEnable()) { | ||||
|             LogUtils.d(TAG, "run() bean.isEnable()"); | ||||
|             TestThread.getInstance(this).start(); | ||||
|             LogUtils.d(TAG, "_TestThread.start()"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         LogUtils.d(TAG, "onDestroy()"); | ||||
|         TestThread.getInstance(this).setIsExit(true); | ||||
|  | ||||
|         _IsRunning = false; | ||||
|     } | ||||
|  | ||||
|     static class TestThread extends Thread { | ||||
|  | ||||
|         volatile static TestThread _TestThread; | ||||
|         Context mContext; | ||||
|         volatile boolean isStarted = false; | ||||
|         volatile boolean isExit = false; | ||||
|  | ||||
|         TestThread(Context context) { | ||||
|             super(); | ||||
|             mContext = context; | ||||
|         } | ||||
|  | ||||
|         public static synchronized TestThread getInstance(Context context) { | ||||
|             if (_TestThread != null) { | ||||
|                 _TestThread.setIsExit(true); | ||||
|             } | ||||
|             _TestThread = new TestThread(context); | ||||
|  | ||||
|             return _TestThread; | ||||
|         } | ||||
|  | ||||
|         public synchronized void setIsExit(boolean isExit) { | ||||
|             this.isExit = isExit; | ||||
|         } | ||||
|  | ||||
|         public boolean isExit() { | ||||
|             return isExit; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|             if (isStarted == false) { | ||||
|                 isStarted = true; | ||||
|                 super.run(); | ||||
|                 LogUtils.d(TAG, "run() start"); | ||||
|  | ||||
|                 while (!isExit()) { | ||||
|                     LogUtils.d(TAG, "run()"); | ||||
|  | ||||
|                     try { | ||||
|                         Thread.sleep(1000); | ||||
|                     } catch (InterruptedException e) { | ||||
|                         LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 LogUtils.d(TAG, "run() exit"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,54 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.threads; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/14 03:46:44 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import cc.winboll.studio.appbase.handlers.MainServiceHandler; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.lang.ref.WeakReference; | ||||
|  | ||||
| public class MainServiceThread extends Thread { | ||||
|  | ||||
|     public static final String TAG = "MainServiceThread"; | ||||
|  | ||||
|     Context mContext; | ||||
|  | ||||
|     // 控制线程是否退出的标志 | ||||
|     volatile boolean isExist = false; | ||||
|  | ||||
|     // 服务Handler, 用于线程发送消息使用 | ||||
|     WeakReference<MainServiceHandler> mwrMainServiceHandler; | ||||
|  | ||||
|     public void setIsExist(boolean isExist) { | ||||
|         this.isExist = isExist; | ||||
|     } | ||||
|  | ||||
|     public boolean isExist() { | ||||
|         return isExist; | ||||
|     } | ||||
|  | ||||
|     public MainServiceThread(Context context, MainServiceHandler handler) { | ||||
|         mContext = context; | ||||
|         mwrMainServiceHandler = new WeakReference<MainServiceHandler>(handler); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void run() { | ||||
|         LogUtils.d(TAG, "run()"); | ||||
|  | ||||
|         while (!isExist()) { | ||||
|             //ToastUtils.show("run()"); | ||||
|             //LogUtils.d(TAG, "run()"); | ||||
|  | ||||
|             try { | ||||
|                 Thread.sleep(1000); | ||||
|             } catch (InterruptedException e) { | ||||
|                 LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|             } | ||||
|         } | ||||
|         LogUtils.d(TAG, "run() exit."); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,186 +0,0 @@ | ||||
| package cc.winboll.studio.appbase.widgets; | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/15 14:41:25 | ||||
|  * @Describe TimeWidget | ||||
|  */ | ||||
| import android.app.PendingIntent; | ||||
| import android.appwidget.AppWidgetManager; | ||||
| import android.appwidget.AppWidgetProvider; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.widget.RemoteViews; | ||||
| import cc.winboll.studio.appbase.R; | ||||
| import cc.winboll.studio.appbase.models.WinBoLLNewsBean; | ||||
| import cc.winboll.studio.appbase.receivers.APPNewsWidgetClickListener; | ||||
| import cc.winboll.studio.libappbase.AppUtils; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.sos.APPModel; | ||||
| import cc.winboll.studio.libappbase.sos.WinBoLL; | ||||
| import java.io.IOException; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Date; | ||||
|  | ||||
| public class APPNewsWidget extends AppWidgetProvider { | ||||
|  | ||||
|     public static final String TAG = "APPNewsWidget"; | ||||
|      | ||||
|     public static final String ACTION_WAKEUP_SERVICE = APPNewsWidget.class.getName() + ".ACTION_WAKEUP_SERVICE"; | ||||
|     public static final String ACTION_RELOAD_REPORT = APPNewsWidget.class.getName() + ".ACTION_RELOAD_REPORT"; | ||||
|  | ||||
|  | ||||
|     volatile static ArrayList<WinBoLLNewsBean> _WinBoLLNewsBeanList; | ||||
|     final static int _MAX_PAGES = 10; | ||||
|     final static int _OnePageLinesCount = 5; | ||||
|     volatile static int _CurrentPageIndex = 0; | ||||
|  | ||||
|     @Override | ||||
|     public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { | ||||
|         initWinBoLLNewsBeanList(context); | ||||
|         for (int appWidgetId : appWidgetIds) { | ||||
|             updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         super.onReceive(context, intent); | ||||
|         initWinBoLLNewsBeanList(context); | ||||
|         if (intent.getAction().equals(ACTION_RELOAD_REPORT)) { | ||||
|             LogUtils.d(TAG, "ACTION_RELOAD_REPORT"); | ||||
|             AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); | ||||
|             int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class)); | ||||
|             for (int appWidgetId : appWidgetIds) { | ||||
|                 updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|             } | ||||
|         }else if (intent.getAction().equals(ACTION_WAKEUP_SERVICE)) { | ||||
|             LogUtils.d(TAG, "ACTION_WAKEUP_SERVICE"); | ||||
|             String szAPPModel = intent.getStringExtra(WinBoLL.EXTRA_APPMODEL); | ||||
|             LogUtils.d(TAG, String.format("szAPPModel %s", szAPPModel)); | ||||
|             if (szAPPModel != null && !szAPPModel.equals("")) { | ||||
|                 try { | ||||
|                     APPModel bean = APPModel.parseStringToBean(szAPPModel, APPModel.class); | ||||
|                     if (bean != null) { | ||||
|                         String szAppPackageName = bean.getAppPackageName(); | ||||
|                         LogUtils.d(TAG, String.format("szAppPackageName %s", szAppPackageName)); | ||||
|                         String szAppMainServiveName = bean.getAppMainServiveName(); | ||||
|                         LogUtils.d(TAG, String.format("szAppMainServiveName %s", szAppMainServiveName)); | ||||
|  | ||||
|                          | ||||
|                         String appName = AppUtils.getAppNameByPackageName(context, szAppPackageName); | ||||
|                         LogUtils.d(TAG, String.format("appName %s", appName)); | ||||
|                         WinBoLLNewsBean winBollNewsBean = new WinBoLLNewsBean(appName); | ||||
|                         SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); | ||||
|                         String currentTime = sdf.format(new Date()); | ||||
|                         StringBuilder sbLine = new StringBuilder(); | ||||
|                         sbLine.append("["); | ||||
|                         sbLine.append(currentTime); | ||||
|                         sbLine.append("] Wake up "); | ||||
|                         sbLine.append(appName); | ||||
|                         winBollNewsBean.setMessage(sbLine.toString()); | ||||
|                          | ||||
|                         addWinBoLLNewsBean(context, winBollNewsBean); | ||||
|  | ||||
|                         AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); | ||||
|                         int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, APPNewsWidget.class)); | ||||
|                         for (int appWidgetId : appWidgetIds) { | ||||
|                             updateAppWidget(context, appWidgetManager, appWidgetId); | ||||
|                         } | ||||
|                     } | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 加入新报告信息 | ||||
|     // | ||||
|     public synchronized static void addWinBoLLNewsBean(Context context, WinBoLLNewsBean bean) { | ||||
|         initWinBoLLNewsBeanList(context); | ||||
|         _WinBoLLNewsBeanList.add(0, bean); | ||||
|         // 控制记录总数 | ||||
|         while (_WinBoLLNewsBeanList.size() > _MAX_PAGES * _OnePageLinesCount) { | ||||
|             _WinBoLLNewsBeanList.remove(_WinBoLLNewsBeanList.size() - 1); | ||||
|         } | ||||
|         WinBoLLNewsBean.saveBeanList(context, _WinBoLLNewsBeanList, WinBoLLNewsBean.class); | ||||
|     } | ||||
|  | ||||
|     synchronized static void initWinBoLLNewsBeanList(Context context) { | ||||
|         if (_WinBoLLNewsBeanList == null) { | ||||
|             _WinBoLLNewsBeanList = new ArrayList<WinBoLLNewsBean>(); | ||||
|             WinBoLLNewsBean.loadBeanList(context, _WinBoLLNewsBeanList, WinBoLLNewsBean.class); | ||||
|         } | ||||
|         if (_WinBoLLNewsBeanList == null) { | ||||
|             _WinBoLLNewsBeanList = new ArrayList<WinBoLLNewsBean>(); | ||||
|             WinBoLLNewsBean.saveBeanList(context, _WinBoLLNewsBeanList, WinBoLLNewsBean.class); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) { | ||||
|         LogUtils.d(TAG, "updateAppWidget(...)"); | ||||
|  | ||||
|         RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_news); | ||||
|         //设置按钮点击事件 | ||||
|         Intent intentPre = new Intent(context, APPNewsWidgetClickListener.class); | ||||
|         intentPre.setAction(APPNewsWidgetClickListener.ACTION_PRE); | ||||
|         PendingIntent pendingIntentPre = PendingIntent.getBroadcast(context, 0, intentPre, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
|         views.setOnClickPendingIntent(R.id.widget_button_pre, pendingIntentPre); | ||||
|         Intent intentNext = new Intent(context, APPNewsWidgetClickListener.class); | ||||
|         intentNext.setAction(APPNewsWidgetClickListener.ACTION_NEXT); | ||||
|         PendingIntent pendingIntentNext = PendingIntent.getBroadcast(context, 0, intentNext, PendingIntent.FLAG_UPDATE_CURRENT); | ||||
|         views.setOnClickPendingIntent(R.id.widget_button_next, pendingIntentNext); | ||||
|  | ||||
|         views.setTextViewText(R.id.tv_msg, getPageInfo()); | ||||
|         views.setTextViewText(R.id.tv_news, getMessage()); | ||||
|         appWidgetManager.updateAppWidget(appWidgetId, views); | ||||
|     } | ||||
|  | ||||
|     public static String getMessage() { | ||||
|         ArrayList<String> msgTemp = new ArrayList<String>(); | ||||
|         if (_WinBoLLNewsBeanList != null) { | ||||
|             int start = _OnePageLinesCount * _CurrentPageIndex; | ||||
|             start = _WinBoLLNewsBeanList.size() > start ? start : _WinBoLLNewsBeanList.size() - 1; | ||||
|             for (int i = start, j = 0; i < _WinBoLLNewsBeanList.size() && j < _OnePageLinesCount && start > -1; i++, j++) { | ||||
|                 msgTemp.add(_WinBoLLNewsBeanList.get(i).getMessage()); | ||||
|             } | ||||
|             String message = String.join("\n", msgTemp); | ||||
|             return message; | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     public static void prePage(Context context) { | ||||
|         if (_WinBoLLNewsBeanList != null) { | ||||
|             if (_CurrentPageIndex > 0) { | ||||
|                 _CurrentPageIndex = _CurrentPageIndex - 1; | ||||
|             } | ||||
|             Intent intentWidget = new Intent(context, APPNewsWidget.class); | ||||
|             intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT); | ||||
|             context.sendBroadcast(intentWidget); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void nextPage(Context context) { | ||||
|         if (_WinBoLLNewsBeanList != null) { | ||||
|             if ((_CurrentPageIndex + 1) * _OnePageLinesCount < _WinBoLLNewsBeanList.size()) { | ||||
|                 _CurrentPageIndex = _CurrentPageIndex + 1; | ||||
|             } | ||||
|             Intent intentWidget = new Intent(context, APPNewsWidget.class); | ||||
|             intentWidget.setAction(APPNewsWidget.ACTION_RELOAD_REPORT); | ||||
|             context.sendBroadcast(intentWidget); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     String getPageInfo() { | ||||
|         if (_WinBoLLNewsBeanList == null) { | ||||
|             return "0/0"; | ||||
|         } | ||||
|         int leftCount = _WinBoLLNewsBeanList.size() % _OnePageLinesCount; | ||||
|         int currentPageCount = _WinBoLLNewsBeanList.size() / _OnePageLinesCount + (leftCount == 0 ?0: 1); | ||||
|         return String.format("%d/%d", _CurrentPageIndex + 1, currentPageCount); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										7
									
								
								appbase/src/main/res/drawable/btn_light_blue.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								appbase/src/main/res/drawable/btn_light_blue.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:shape="rectangle"> | ||||
|     <solid android:color="#81C7F5"/> <!-- 浅蓝色填充 --> | ||||
|     <corners android:radius="8dp"/> <!-- 8dp 圆角 --> | ||||
| </shape> | ||||
|  | ||||
| @@ -1,11 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M6.5,20Q4.22,20 2.61,18.43 1,16.85 1,14.58 1,12.63 2.17,11.1 3.35,9.57 5.25,9.15 5.88,6.85 7.75,5.43 9.63,4 12,4 14.93,4 16.96,6.04 19,8.07 19,11 20.73,11.2 21.86,12.5 23,13.78 23,15.5 23,17.38 21.69,18.69 20.38,20 18.5,20M6.5,18H18.5Q19.55,18 20.27,17.27 21,16.55 21,15.5 21,14.45 20.27,13.73 19.55,13 18.5,13H17V11Q17,8.93 15.54,7.46 14.08,6 12,6 9.93,6 8.46,7.46 7,8.93 7,11H6.5Q5.05,11 4.03,12.03 3,13.05 3,14.5 3,15.95 4.03,17 5.05,18 6.5,18M12,12Z"/> | ||||
|  | ||||
| </vector> | ||||
| @@ -3,214 +3,45 @@ | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
| 	android:layout_height="match_parent" | ||||
| 	android:padding="16dp"> | ||||
|  | ||||
| 	<android.widget.Toolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:id="@+id/toolbar"/> | ||||
|  | ||||
| 	<ScrollView | ||||
| 	<LinearLayout | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
| 		android:layout_weight="1" | ||||
| 		android:orientation="vertical" | ||||
| 		android:gravity="center_vertical" | ||||
| 		android:spacing="12dp"> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 		<Button | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:orientation="vertical" | ||||
| 			android:gravity="center"> | ||||
| 			android:text="应用崩溃测试" | ||||
| 			android:textSize="16sp" | ||||
| 			android:textColor="@android:color/white" | ||||
| 			android:background="#81C7F5" | ||||
| 			android:paddingVertical="12dp" | ||||
| 			android:layout_marginHorizontal="24dp" | ||||
| 			android:onClick="onCrashTest"/> | ||||
|  | ||||
| 			<LinearLayout | ||||
| 				android:orientation="vertical" | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="0dp" | ||||
| 				android:layout_weight="1.0" | ||||
| 				android:gravity="center_horizontal"> | ||||
| 		<Button | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="应用日志测试" | ||||
| 			android:textSize="16sp" | ||||
| 			android:textColor="@android:color/white" | ||||
| 			android:background="#81C7F5" | ||||
| 			android:paddingVertical="12dp" | ||||
| 			android:layout_marginHorizontal="24dp" | ||||
| 			android:onClick="onLogTest"/> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:layout_width="wrap_content" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="Hello, WinBoLL!"/> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:layout_width="wrap_content" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="Android版本10的代号是“Q”,API级别是29。   Android 10开始谷歌不再公开使用甜品作为版本代号,但内部仍保留了大量与“Q”相关的元素。Android 10本身并没有严格对应某个特定的Java版本,但在开发Android 10应用时,通常可以使用Java 8或更高版本。   Java 8为Android开发带来了诸如Lambda表达式、方法引用等新特性,能提高开发效率和代码可读性,与Android 10开发适配良好。Java 9及更高版本也可用于Android 10开发,能使用一些新的语言特性和API,但可能需要注意兼容性和配置问题。"/> | ||||
|  | ||||
| 				<HorizontalScrollView | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content"> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="horizontal" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:gravity="right|center_vertical" | ||||
| 						android:layout_width="wrap_content"> | ||||
|  | ||||
| 						<CheckBox | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="Debug Mode" | ||||
| 							android:layout_weight="1.0" | ||||
| 							android:onClick="onSwitchDebugMode" | ||||
| 							android:id="@+id/activitymainCheckBox1"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="Test Application CrashReport" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestApplicationCrashReport"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="PreviewGlobalCrashActivity" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onPreviewGlobalCrashActivity"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 				</HorizontalScrollView> | ||||
|  | ||||
| 				<ScrollView | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="400dp"> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="vertical" | ||||
| 						android:layout_width="match_parent" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:gravity="right"> | ||||
|  | ||||
| 						<LinearLayout | ||||
| 							android:orientation="horizontal" | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content"> | ||||
|  | ||||
| 							<Button | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content" | ||||
| 								android:text="StartCenter" | ||||
| 								android:textAllCaps="false" | ||||
| 								android:onClick="onStartCenter"/> | ||||
|  | ||||
| 							<Button | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content" | ||||
| 								android:text="StopCenter" | ||||
| 								android:textAllCaps="false" | ||||
| 								android:onClick="onStopCenter"/> | ||||
|  | ||||
| 						</LinearLayout> | ||||
|  | ||||
| 						<HorizontalScrollView | ||||
| 							android:layout_width="match_parent" | ||||
| 							android:layout_height="wrap_content"> | ||||
|  | ||||
| 							<LinearLayout | ||||
| 								android:orientation="horizontal" | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content"> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="SartTestDemoService" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onSartTestDemoService"/> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="StopTestDemoService" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onStopTestDemoService"/> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="StopTestDemoServiceNoSettings" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onStopTestDemoServiceNoSettings"/> | ||||
|  | ||||
| 							</LinearLayout> | ||||
|  | ||||
| 						</HorizontalScrollView> | ||||
|  | ||||
| 						<HorizontalScrollView | ||||
| 							android:layout_width="match_parent" | ||||
| 							android:layout_height="wrap_content"> | ||||
|  | ||||
| 							<LinearLayout | ||||
| 								android:orientation="horizontal" | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content"> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="SartTestDemoBindService" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onSartTestDemoBindService"/> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="StopTestDemoBindService" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onStopTestDemoBindService"/> | ||||
|  | ||||
| 								<Button | ||||
| 									android:layout_width="wrap_content" | ||||
| 									android:layout_height="wrap_content" | ||||
| 									android:text="StopTestDemoBindServiceNoSettings" | ||||
| 									android:textAllCaps="false" | ||||
| 									android:onClick="onStopTestDemoBindServiceNoSettings"/> | ||||
|  | ||||
| 							</LinearLayout> | ||||
|  | ||||
| 						</HorizontalScrollView> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="TestStopMainServiceWithoutSettingEnable" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestStopMainServiceWithoutSettingEnable"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="TestUseComponentStartService" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestUseComponentStartService"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="TestDemoServiceSOS" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestDemoServiceSOS"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="TestOpenNewActivity" | ||||
| 							android:textAllCaps="false" | ||||
| 							android:onClick="onTestOpenNewActivity"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 				</ScrollView> | ||||
|  | ||||
| 			</LinearLayout> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 	</ScrollView> | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
|   | ||||
| @@ -1,43 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
|     <android.widget.Toolbar | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
| 		android:id="@+id/toolbar"/> | ||||
|      | ||||
| 	<TextView | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="NewActivity"/> | ||||
|  | ||||
|     <Button | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="CloseThisActivity" | ||||
|         android:textAllCaps="false" | ||||
|         android:onClick="onCloseThisActivity"/> | ||||
|  | ||||
|     <Button | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="CloseAllActivity" | ||||
|         android:textAllCaps="false" | ||||
|         android:onClick="onCloseAllActivity"/> | ||||
|  | ||||
|     <Button | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="New2Activity" | ||||
|         android:textAllCaps="false" | ||||
|         android:onClick="onNew2Activity"/> | ||||
|  | ||||
|      | ||||
|      | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -1,43 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
|     <android.widget.Toolbar | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
| 		android:id="@+id/toolbar"/> | ||||
|  | ||||
| 	<TextView | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="New2Activity"/> | ||||
|  | ||||
| 	<Button | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="CloseThisActivity" | ||||
| 		android:textAllCaps="false" | ||||
| 		android:onClick="onCloseThisActivity"/> | ||||
|  | ||||
| 	<Button | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="CloseAllActivity" | ||||
| 		android:textAllCaps="false" | ||||
| 		android:onClick="onCloseAllActivity"/> | ||||
|  | ||||
| 	<Button | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="NewActivity" | ||||
| 		android:textAllCaps="false" | ||||
| 		android:onClick="onNewActivity"/> | ||||
|  | ||||
| 	 | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -1,51 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent" | ||||
| 	android:orientation="vertical" | ||||
| 	android:background="#FFFFFFFF"> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:gravity="right|center_vertical"> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="0dp" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:id="@+id/tv_title" | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:text="WinBoLLNews" | ||||
| 			android:textStyle="bold" | ||||
| 			android:textSize="16sp"/> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="48dp" | ||||
| 			android:layout_height="48dp" | ||||
| 			android:text="⇦" | ||||
| 			android:id="@+id/widget_button_pre"/> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="48dp" | ||||
| 			android:layout_height="48dp" | ||||
| 			android:text="⇨" | ||||
| 			android:id="@+id/widget_button_next"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
|     <TextView | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:id="@+id/tv_msg"/> | ||||
|      | ||||
| 	<TextView | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:id="@+id/tv_news" | ||||
| 		android:layout_weight="1.0"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -1,6 +1,8 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|      | ||||
|      | ||||
|     <item | ||||
|         android:id="@+id/item_home" | ||||
|         android:title="WinBoLL Home" | ||||
|         android:icon="@drawable/ic_winboll"/> | ||||
| </menu> | ||||
|   | ||||
| @@ -1,7 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:minWidth="200dp" | ||||
|     android:minHeight="100dp" | ||||
|     android:updatePeriodMillis="1000" | ||||
|     android:initialLayout="@layout/widget_news"> | ||||
| </appwidget-provider> | ||||
							
								
								
									
										35
									
								
								apputils/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								apputils/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| # APPUtils | ||||
|  | ||||
| #### 介绍 | ||||
| 应用开发工具套件类 | ||||
|  | ||||
| #### 软件架构 | ||||
| 适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。 | ||||
| 也适配安卓应用 [AndroidIDE] 的 Gradle 编译结构。 | ||||
|  | ||||
|  | ||||
| #### Gradle 编译说明 | ||||
| 调试版编译命令 :gradle assembleBetaDebug | ||||
| 阶段版编译命令 :git pull && bash .winboll/bashPublishAPKAddTag.sh apputils | ||||
| 阶段版类库发布命令 :git pull &&bash .winboll/bashPublishLIBAddTag.sh libapputils | ||||
|  | ||||
| #### 使用说明 | ||||
|  | ||||
| #### 参与贡献 | ||||
|  | ||||
| 1.  Fork 本仓库 | ||||
| 2.  新建 Feat_xxx 分支 | ||||
| 3.  提交代码 : ZhanGSKen(ZhanGSKen<zhangsken@188.com>) | ||||
| 4.  新建 Pull Request | ||||
|  | ||||
|  | ||||
| #### 特技 | ||||
|  | ||||
| 1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md | ||||
| 2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) | ||||
| 3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 | ||||
| 4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 | ||||
| 5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) | ||||
| 6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) | ||||
|  | ||||
| #### 参考文档 | ||||
| @@ -29,7 +29,7 @@ android { | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // 项目模块目录的 build.gradle 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.3"  | ||||
|         versionName "15.10"  | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Tue Apr 29 14:08:11 HKT 2025 | ||||
| stageCount=4 | ||||
| #Mon Sep 29 01:16:05 HKT 2025 | ||||
| stageCount=3 | ||||
| libraryProject=libapputils | ||||
| baseVersion=15.3 | ||||
| publishVersion=15.3.3 | ||||
| baseVersion=15.10 | ||||
| publishVersion=15.10.2 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.3.4 | ||||
| baseBetaVersion=15.10.3 | ||||
|   | ||||
| @@ -2,14 +2,20 @@ | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.apputils"> | ||||
|  | ||||
| 	 | ||||
| 	<!-- 读取外部存储权限(Android 10 以下) --> | ||||
| 	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | ||||
| 		 | ||||
|     <application | ||||
|         android:name=".App" | ||||
|         android:allowBackup="true" | ||||
|         android:icon="@drawable/ic_winboll" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/MyUtilsTheme" | ||||
|         android:supportsRtl="true"> | ||||
|         android:supportsRtl="true" | ||||
|         android:resizeableActivity="true" | ||||
| 		android:screenOrientation="unspecified" | ||||
| 		android:requestLegacyExternalStorage="true"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
| @@ -35,6 +41,8 @@ | ||||
|  | ||||
|         <activity android:name=".QRCodeDecodeActivity"/> | ||||
|  | ||||
|         <activity android:name=".QRGeneratorActivity"/> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| </manifest> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| package cc.winboll.studio.apputils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/12/08 15:10:51 | ||||
|  * @Describe 全局应用类 | ||||
|  */ | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| package cc.winboll.studio.apputils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/01/03 11:02:49 | ||||
|  * @Describe 一个可以浏览随 APP 附带的 Html 文档的窗口 | ||||
|  */ | ||||
| @@ -15,23 +15,11 @@ import android.view.MenuItem; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.apputils.R; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBollActivity; | ||||
| import cc.winboll.studio.libapputils.views.SimpleWebView; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
|  | ||||
| public class AssetsHtmlActivity extends WinBollActivityBase implements IWinBollActivity { | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return super.getActivity(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
| public class AssetsHtmlActivity extends Activity { | ||||
|  | ||||
|     public static final String TAG = "AssetsHtmlActivity"; | ||||
|  | ||||
| @@ -43,12 +31,7 @@ public class AssetsHtmlActivity extends WinBollActivityBase implements IWinBollA | ||||
|  | ||||
|     // Assets 文件夹里的 Html 文件的名称 | ||||
|     String mszHtmlFileName; | ||||
| // | ||||
| //    @Override | ||||
| //    public Activity getActivity() { | ||||
| //        return this; | ||||
| //    } | ||||
|  | ||||
|      | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
| @@ -57,7 +40,7 @@ public class AssetsHtmlActivity extends WinBollActivityBase implements IWinBollA | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
| //        if (item.getItemId() == android.R.id.home) { | ||||
| //            WinBollActivityManager.getInstance(this).finish(this); | ||||
| //            WinBoLLActivityManager.getInstance(this).finish(this); | ||||
| //        } | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|   | ||||
| @@ -15,9 +15,10 @@ import android.widget.Toolbar; | ||||
| import cc.winboll.studio.apputils.R; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
| import cc.winboll.studio.libappbase.utils.ToastUtils; | ||||
| import cc.winboll.studio.libappbase.ToastUtils; | ||||
| import java.util.List; | ||||
| import java.util.Set; | ||||
| import cc.winboll.studio.libappbase.LogActivity; | ||||
|  | ||||
| final public class MainActivity extends Activity { | ||||
|  | ||||
| @@ -26,21 +27,21 @@ final public class MainActivity extends Activity { | ||||
|     public static final int REQUEST_QRCODEDECODE_ACTIVITY = 0; | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|     LogView mLogView; | ||||
|     //LogView mLogView; | ||||
| // | ||||
| //    @Override | ||||
| //    public Activity getActivity() { | ||||
| //        return this; | ||||
| //    } | ||||
|  | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_main); | ||||
|  | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|         mLogView.start(); | ||||
| //        mLogView = findViewById(R.id.logview); | ||||
| //        mLogView.start(); | ||||
|  | ||||
|         // 初始化工具栏 | ||||
|         mToolbar = findViewById(R.id.toolbar); | ||||
| @@ -60,9 +61,9 @@ final public class MainActivity extends Activity { | ||||
|         //if (prosessIntents(getIntent())) return; | ||||
|         // 以下正常创建主窗口 | ||||
|  | ||||
| //        // 设置 WinBoll 应用 UI 类型 | ||||
| //        WinBollApplication.setWinBollUI_TYPE(WinBollApplication.WinBollUI_TYPE.Aplication); | ||||
| //        //ToastUtils.show("WinBollUI_TYPE " + WinBollApplication.getWinBollUI_TYPE()); | ||||
| //        // 设置 WinBoLL 应用 UI 类型 | ||||
| //        WinBoLLApplication.setWinBoLLUI_TYPE(WinBoLLApplication.WinBoLLUI_TYPE.Aplication); | ||||
| //        //ToastUtils.show("WinBoLLUI_TYPE " + WinBoLLApplication.getWinBoLLUI_TYPE()); | ||||
| //        LogUtils.d(TAG, "BuildConfig.DEBUG : " + Boolean.toString(BuildConfig.DEBUG)); | ||||
|     } | ||||
|  | ||||
| @@ -77,7 +78,7 @@ final public class MainActivity extends Activity { | ||||
|                 if (intent.getAction() != null) { | ||||
| //                    if (intent.getAction().equals(cc.winboll.studio.libapputils.intent.action.DEBUGVIEW)) { | ||||
| //                        App.setIsDebug(true); | ||||
| //                        //ToastUtils.show!("WinBollApplication.setIsDebug(true) by action : " + intent.getAction()); | ||||
| //                        //ToastUtils.show!("WinBoLLApplication.setIsDebug(true) by action : " + intent.getAction()); | ||||
| // | ||||
| //                    } | ||||
|                 } | ||||
| @@ -130,12 +131,12 @@ final public class MainActivity extends Activity { | ||||
|     protected void onPostCreate(Bundle savedInstanceState) { | ||||
|         super.onPostCreate(savedInstanceState); | ||||
|         // 缓存当前 activity | ||||
|         //WinBollActivityManager.getInstance(this).add(this); | ||||
|         //WinBoLLActivityManager.getInstance(this).add(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         //WinBollActivityManager.getInstance(this).registeRemove(this); | ||||
|         //WinBoLLActivityManager.getInstance(this).registeRemove(this); | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
| @@ -145,13 +146,21 @@ final public class MainActivity extends Activity { | ||||
|     } | ||||
|  | ||||
|     public void onTestLogActivity(View view) { | ||||
| //        Intent intent = new Intent(this, LogActivity.class); | ||||
| //        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); | ||||
| //        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); | ||||
| //        startActivity(intent); | ||||
| 		/* 分屏代码有效 | ||||
| 		// 1. 创建启动 SecondActivity 的 Intent | ||||
| 		Intent splitIntent = new Intent(MainActivity.this, LogActivity.class); | ||||
|  | ||||
|         //WinBollActivityManager.getInstance().printAvtivityListInfo(); | ||||
|         //WinBollActivityManager.getInstance(this).startWinBollActivity(this, LogActivity.class); | ||||
| 		// 2. 添加分屏启动必需的两个标志(API 30 兼容) | ||||
| 		// FLAG_ACTIVITY_LAUNCH_ADJACENT:相邻分屏显示 | ||||
| 		// FLAG_ACTIVITY_NEW_TASK:分屏需要新任务栈 | ||||
| 		splitIntent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT  | ||||
| 							 | Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|  | ||||
| 		// 3. 启动分屏活动(若设备不支持分屏,会默认全屏启动) | ||||
| 		startActivity(splitIntent); | ||||
| 		*/ | ||||
|  | ||||
| 		LogActivity.startLogActivity(this); | ||||
|     } | ||||
|  | ||||
|     // | ||||
| @@ -165,7 +174,7 @@ final public class MainActivity extends Activity { | ||||
|  | ||||
| //        if (intent.getAction().equals(StringToQrCodeView.ACTION_UNITTEST_QRCODE)) { | ||||
| //            try { | ||||
| //                WinBollActivity clazzActivity = UnitTestActivity.class.newInstance(); | ||||
| //                WinBoLLActivity clazzActivity = UnitTestActivity.class.newInstance(); | ||||
| //                String tag = clazzActivity.getTag(); | ||||
| //                LogUtils.d(TAG, "String tag = clazzActivity.getTag(); tag " + tag); | ||||
| //                Intent subIntent = new Intent(this, UnitTestActivity.class); | ||||
| @@ -183,8 +192,8 @@ final public class MainActivity extends Activity { | ||||
| //                } | ||||
| // | ||||
| //                Files.copy(Paths.get(szSrcPath), Paths.get(file.getPath())); | ||||
| //                //startWinBollActivity(subIntent, tag); | ||||
| //                WinBollActivityManager.getInstance(this).startWinBollActivity(this, subIntent, UnitTestActivity.class); | ||||
| //                //startWinBoLLActivity(subIntent, tag); | ||||
| //                WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(this, subIntent, UnitTestActivity.class); | ||||
| //            } catch (IllegalAccessException | InstantiationException | IOException e) { | ||||
| //                LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
| //                // 函数处理异常返回失败 | ||||
| @@ -201,8 +210,8 @@ final public class MainActivity extends Activity { | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         //ToastUtils.show("onCreateOptionsMenu"); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
| //        if (isAddWinBollToolBar()) { | ||||
| //            //ToastUtils.show("mIWinBoll.isAddWinBollToolBar()"); | ||||
| //        if (isAddWinBoLLToolBar()) { | ||||
| //            //ToastUtils.show("mIWinBoLL.isAddWinBoLLToolBar()"); | ||||
| //            getMenuInflater().inflate(R.menu.toolbar_winboll_shared_main, menu); | ||||
| //        } | ||||
|         if (App.isDebuging()) { | ||||
| @@ -217,10 +226,9 @@ final public class MainActivity extends Activity { | ||||
|         if (item.getItemId() == R.id.item_exit) { | ||||
|             //exit(); | ||||
|             return true; | ||||
|         } else if (item.getItemId() == R.id.item_teststringtoqrcodeview) { | ||||
|             Intent intent = new Intent(this, TestStringToQRCodeViewActivity.class); | ||||
|             startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY); | ||||
|             //WinBollActivityManager.getInstance(this).startWinBollActivity(this, TestStringToQrCodeViewActivity.class); | ||||
|         } else if (item.getItemId() == R.id.item_testqrgeneratoractivity) { | ||||
|             Intent intent = new Intent(this, QRGeneratorActivity.class); | ||||
|             startActivity(intent); | ||||
|         } else if (item.getItemId() == R.id.item_testqrcodedecodeactivity) { | ||||
|             Intent intent = new Intent(this, QRCodeDecodeActivity.class); | ||||
|             startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY); | ||||
| @@ -230,13 +238,13 @@ final public class MainActivity extends Activity { | ||||
|             } | ||||
|             return true; | ||||
|         } else if (item.getItemId() == R.id.item_log) { | ||||
|             //WinBollActivityManager.getInstance(this).startWinBollActivity(this, LogActivity.class); | ||||
|             //WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(this, LogActivity.class); | ||||
|             return true; | ||||
|         } else if (item.getItemId() == R.id.item_exitdebug) { | ||||
|             //AboutView.setApp2NormalMode(this); | ||||
|             return true; | ||||
|         } else if (item.getItemId() == android.R.id.home) { | ||||
|             //WinBollActivityManager.getInstance(this).finish(this); | ||||
|             //WinBoLLActivityManager.getInstance(this).finish(this); | ||||
|             return true; | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item); | ||||
| @@ -247,7 +255,7 @@ final public class MainActivity extends Activity { | ||||
| // | ||||
| //            @Override | ||||
| //            public void onYes() { | ||||
| //                //WinBollActivityManager.getInstance(getApplicationContext()).finishAll(); | ||||
| //                //WinBoLLActivityManager.getInstance(getApplicationContext()).finishAll(); | ||||
| //            } | ||||
| // | ||||
| //            @Override | ||||
| @@ -260,28 +268,28 @@ final public class MainActivity extends Activity { | ||||
|  | ||||
|     @Override | ||||
|     public void onBackPressed() { | ||||
| //        if (WinBollActivityManager.getInstance(getApplicationContext()).isFirstIWinBollActivity(this)) { | ||||
| //        if (WinBoLLActivityManager.getInstance(getApplicationContext()).isFirstIWinBoLLActivity(this)) { | ||||
| //            exit(); | ||||
| //        } else { | ||||
| //            WinBollActivityManager.getInstance(this).finish(this); | ||||
| //            WinBoLLActivityManager.getInstance(this).finish(this); | ||||
| //            super.onBackPressed(); | ||||
| //        } | ||||
|     } | ||||
|  | ||||
|      | ||||
|  | ||||
|     public void onTestAssetsHtmlActivity(View view) { | ||||
|         Intent intent = new Intent(this, AssetsHtmlActivity.class); | ||||
|         intent.putExtra(AssetsHtmlActivity.EXTRA_HTMLFILENAME, "javascript_test.html"); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); | ||||
|         startActivity(intent); | ||||
|         //WinBollActivityManager.getInstance(this).startWinBollActivity(this, intent, AssetsHtmlActivity.class); | ||||
|         //WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(this, intent, AssetsHtmlActivity.class); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         mLogView.start(); | ||||
|         //mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     /*@Override | ||||
|   | ||||
| @@ -1,89 +1,323 @@ | ||||
| package cc.winboll.studio.apputils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> | ||||
|  * @Date 2025/01/18 10:32:21 | ||||
|  * @Describe 二维码扫码解码窗口 | ||||
|  * @Describe 二维码解码窗口 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.app.AlertDialog; | ||||
| import android.content.DialogInterface; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.BitmapFactory; | ||||
| import android.graphics.Canvas; | ||||
| import android.graphics.ColorMatrix; | ||||
| import android.graphics.ColorMatrixColorFilter; | ||||
| import android.graphics.Paint; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.provider.MediaStore; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.ScrollView; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.apputils.R; | ||||
| import com.google.zxing.BarcodeFormat; | ||||
| import com.google.zxing.BinaryBitmap; | ||||
| import com.google.zxing.DecodeHintType; | ||||
| import com.google.zxing.LuminanceSource; | ||||
| import com.google.zxing.MultiFormatReader; | ||||
| import com.google.zxing.NotFoundException; | ||||
| import com.google.zxing.RGBLuminanceSource; | ||||
| import com.google.zxing.Result; | ||||
| import com.google.zxing.ResultPoint; | ||||
| import com.google.zxing.common.HybridBinarizer; | ||||
| import com.journeyapps.barcodescanner.BarcodeCallback; | ||||
| import com.journeyapps.barcodescanner.BarcodeResult; | ||||
| import com.journeyapps.barcodescanner.DecoratedBarcodeView; | ||||
| import com.journeyapps.barcodescanner.DefaultDecoderFactory; | ||||
| import java.io.InputStream; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Hashtable; | ||||
| import java.util.List; | ||||
|  | ||||
| public class QRCodeDecodeActivity extends Activity { | ||||
|  | ||||
|     public static final String TAG = "QRCodeDecodeActivity"; | ||||
|  | ||||
|     public static final String EXTRA_RESULT = "EXTRA_RESULT"; | ||||
|     private static final int REQUEST_CAMERA_PERMISSION = 1; | ||||
|     private static final int REQUEST_PICK_IMAGE = 2; | ||||
|     private static final int REQUEST_READ_STORAGE_PERMISSION = 3; | ||||
|     // 图片压缩阈值:超过1000px时压缩,避免内存溢出和解码效率低 | ||||
|     private static final int MAX_BITMAP_SIZE = 1000; | ||||
|  | ||||
|     TextView resultTextView; | ||||
|     DecoratedBarcodeView barcodeView; | ||||
|  | ||||
| //    @Override | ||||
| //    public Activity getActivity() { | ||||
| //        return this; | ||||
| //    } | ||||
|     private TextView resultTextView; | ||||
|     private DecoratedBarcodeView barcodeView; | ||||
|     private Button btnDecodeFromAlbum; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_qrcodedecode); | ||||
|  | ||||
|         // 初始化工具栏 | ||||
| //        Toolbar mToolbar = findViewById(R.id.toolbar); | ||||
| //        setActionBar(mToolbar); | ||||
|  | ||||
|         //resultTextView = findViewById(R.id.activityqrcodedecodeTextView1); | ||||
|         barcodeView = findViewById(R.id.activityqrcodedecodeDecoratedBarcodeView1); | ||||
|         // 请求相机权限 | ||||
| //        if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) | ||||
| //            != PackageManager.PERMISSION_GRANTED) { | ||||
| //            ActivityCompat.requestPermissions(this, | ||||
| //                                              new String[]{android.Manifest.permission.CAMERA}, | ||||
| //                                              REQUEST_CAMERA_PERMISSION); | ||||
| //        } else { | ||||
| //            startScanning(); | ||||
| //        } | ||||
|         startScanning(); | ||||
|         initToolbar(); | ||||
|         initViews(); | ||||
|         checkCameraPermission(); | ||||
|         setAlbumDecodeClickListener(); | ||||
|     } | ||||
|  | ||||
|     private void startScanning() { | ||||
|         barcodeView.getBarcodeView().setDecoderFactory(null); | ||||
|         barcodeView.decodeContinuous(barcodeCallback); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onRequestPermissionsResult(int requestCode, | ||||
|                                            String[] permissions, int[] grantResults) { | ||||
|         if (requestCode == REQUEST_CAMERA_PERMISSION) { | ||||
|             if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
|                 startScanning(); | ||||
|             } else { | ||||
|                 // 权限被拒绝的处理 | ||||
|     private void initToolbar() { | ||||
|         Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); | ||||
|         if (mToolbar != null) { | ||||
|             setActionBar(mToolbar); | ||||
|             if (getActionBar() != null) { | ||||
|                 getActionBar().setDisplayHomeAsUpEnabled(true); | ||||
|                 mToolbar.setNavigationOnClickListener(new View.OnClickListener() { | ||||
| 						@Override | ||||
| 						public void onClick(View v) { | ||||
| 							finish(); | ||||
| 						} | ||||
| 					}); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     BarcodeCallback barcodeCallback = new BarcodeCallback(){ | ||||
|     private void initViews() { | ||||
|         resultTextView = (TextView) findViewById(R.id.activityqrcodedecodeTextView1); | ||||
|         barcodeView = (DecoratedBarcodeView) findViewById(R.id.activityqrcodedecodeDecoratedBarcodeView1); | ||||
|         btnDecodeFromAlbum = (Button) findViewById(R.id.btn_decode_from_album); | ||||
|         // 初始化扫码解码器(支持所有常见码制,避免仅支持QR_CODE的局限) | ||||
|         List<BarcodeFormat> formats = new ArrayList<BarcodeFormat>(); | ||||
|         formats.add(BarcodeFormat.QR_CODE); | ||||
|         formats.add(BarcodeFormat.CODE_128); | ||||
|         formats.add(BarcodeFormat.EAN_13); | ||||
|         barcodeView.getBarcodeView().setDecoderFactory(new DefaultDecoderFactory(formats)); | ||||
|     } | ||||
|  | ||||
|     private void setAlbumDecodeClickListener() { | ||||
|         btnDecodeFromAlbum.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) | ||||
|                         != PackageManager.PERMISSION_GRANTED) { | ||||
| 						requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, | ||||
| 										   REQUEST_READ_STORAGE_PERMISSION); | ||||
| 					} else { | ||||
| 						openAlbum(); | ||||
| 					} | ||||
| 				} | ||||
| 			}); | ||||
|     } | ||||
|  | ||||
|     private void openAlbum() { | ||||
|         Intent pickImageIntent = new Intent(Intent.ACTION_PICK); | ||||
|         pickImageIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); | ||||
|         startActivityForResult(pickImageIntent, REQUEST_PICK_IMAGE); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onActivityResult(int requestCode, int resultCode, Intent data) { | ||||
|         super.onActivityResult(requestCode, resultCode, data); | ||||
|         if (requestCode == REQUEST_PICK_IMAGE && resultCode == RESULT_OK && data != null) { | ||||
|             Uri selectedImageUri = data.getData(); | ||||
|             if (selectedImageUri != null) { | ||||
|                 try { | ||||
|                     // 1. 读取图片并压缩(关键优化:避免大图片解码失败) | ||||
|                     InputStream imageStream = getContentResolver().openInputStream(selectedImageUri); | ||||
|                     BitmapFactory.Options options = new BitmapFactory.Options(); | ||||
|                     options.inJustDecodeBounds = true; // 先获取图片尺寸,不加载像素 | ||||
|                     BitmapFactory.decodeStream(imageStream, null, options); | ||||
|                     imageStream.close(); // 关闭流,重新读取 | ||||
|  | ||||
|                     // 计算压缩比例:超过MAX_BITMAP_SIZE时按比例压缩 | ||||
|                     options.inSampleSize = calculateInSampleSize(options, MAX_BITMAP_SIZE, MAX_BITMAP_SIZE); | ||||
|                     options.inJustDecodeBounds = false; // 开始加载压缩后的像素 | ||||
|                     imageStream = getContentResolver().openInputStream(selectedImageUri); | ||||
|                     Bitmap originalBitmap = BitmapFactory.decodeStream(imageStream, null, options); | ||||
|                     imageStream.close(); | ||||
|  | ||||
|                     if (originalBitmap == null) { | ||||
|                         showToast("图片损坏,无法解析"); | ||||
|                         return; | ||||
|                     } | ||||
|  | ||||
|                     // 2. 图片预处理:转为灰度图+提高对比度(解决模糊/低对比度图片识别问题) | ||||
|                     Bitmap processedBitmap = processBitmap(originalBitmap); | ||||
|  | ||||
|                     // 3. 解码预处理后的图片 | ||||
|                     String decodeResult = decodeQrFromBitmap(processedBitmap); | ||||
|  | ||||
|                     // 4. 结果处理 | ||||
|                     if (decodeResult != null && !decodeResult.isEmpty()) { | ||||
|                         resultTextView.setText("图片解码结果:" + decodeResult); | ||||
|                         showDecodeResultDialog(decodeResult); | ||||
|                         returnResultToPreviousPage(decodeResult); | ||||
|                     } else { | ||||
|                         // 尝试直接解码原图(防止预处理过度导致识别失败) | ||||
|                         String originalResult = decodeQrFromBitmap(originalBitmap); | ||||
|                         if (originalResult != null && !originalResult.isEmpty()) { | ||||
|                             resultTextView.setText("图片解码结果:" + originalResult); | ||||
|                             showDecodeResultDialog(originalResult); | ||||
|                             returnResultToPreviousPage(originalResult); | ||||
|                         } else { | ||||
|                             new AlertDialog.Builder(this) | ||||
| 								.setTitle("解码失败") | ||||
| 								.setMessage("图片中未识别到二维码/条码,建议选择清晰、完整的图片") | ||||
| 								.setPositiveButton("确定", new DialogInterface.OnClickListener() { | ||||
| 									@Override | ||||
| 									public void onClick(DialogInterface dialog, int which) { | ||||
| 										dialog.dismiss(); | ||||
| 									} | ||||
| 								}) | ||||
| 								.show(); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     // 回收Bitmap,避免内存泄漏 | ||||
|                     if (!originalBitmap.isRecycled()) originalBitmap.recycle(); | ||||
|                     if (!processedBitmap.isRecycled() && processedBitmap != originalBitmap) { | ||||
|                         processedBitmap.recycle(); | ||||
|                     } | ||||
|  | ||||
|                 } catch (Exception e) { | ||||
|                     e.printStackTrace(); | ||||
|                     showToast("图片处理失败:" + e.getMessage()); | ||||
|                 } | ||||
|             } else { | ||||
|                 showToast("未选择图片"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 核心优化1:计算图片压缩比例 | ||||
|      */ | ||||
|     private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { | ||||
|         final int height = options.outHeight; | ||||
|         final int width = options.outWidth; | ||||
|         int inSampleSize = 1; | ||||
|  | ||||
|         if (height > reqHeight || width > reqWidth) { | ||||
|             final int halfHeight = height / 2; | ||||
|             final int halfWidth = width / 2; | ||||
|             // 找到最接近reqWidth/reqHeight的压缩比例(2的倍数,保证图片质量) | ||||
|             while ((halfHeight / inSampleSize) >= reqHeight | ||||
| 				   && (halfWidth / inSampleSize) >= reqWidth) { | ||||
|                 inSampleSize *= 2; | ||||
|             } | ||||
|         } | ||||
|         return inSampleSize; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 核心优化2:图片预处理(灰度化+提高对比度) | ||||
|      * 解决模糊、低亮度、低对比度图片识别率低的问题 | ||||
|      */ | ||||
|     private Bitmap processBitmap(Bitmap bitmap) { | ||||
|         int width = bitmap.getWidth(); | ||||
|         int height = bitmap.getHeight(); | ||||
|  | ||||
|         // 创建灰度图 | ||||
|         Bitmap grayBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); | ||||
|         Canvas canvas = new Canvas(grayBitmap); | ||||
|         Paint paint = new Paint(); | ||||
|  | ||||
|         // 1. 灰度化矩阵 | ||||
|         ColorMatrix grayMatrix = new ColorMatrix(); | ||||
|         grayMatrix.setSaturation(0); // 饱和度设为0,转为灰度 | ||||
|  | ||||
|         // 2. 提高对比度矩阵(alpha=1.5,亮度=0,可根据需求调整) | ||||
|         ColorMatrix contrastMatrix = new ColorMatrix(); | ||||
|         contrastMatrix.set(new float[]{ | ||||
| 							   1.5f, 0, 0, 0, 0,  // 红通道对比度 | ||||
| 							   0, 1.5f, 0, 0, 0,  // 绿通道对比度 | ||||
| 							   0, 0, 1.5f, 0, 0,  // 蓝通道对比度 | ||||
| 							   0, 0, 0, 1f, 0     // alpha通道不变 | ||||
| 						   }); | ||||
|  | ||||
|         // 合并灰度+对比度矩阵 | ||||
|         ColorMatrix combinedMatrix = new ColorMatrix(); | ||||
|         combinedMatrix.postConcat(grayMatrix); | ||||
|         combinedMatrix.postConcat(contrastMatrix); | ||||
|  | ||||
|         paint.setColorFilter(new ColorMatrixColorFilter(combinedMatrix)); | ||||
|         canvas.drawBitmap(bitmap, 0, 0, paint); | ||||
|  | ||||
|         return grayBitmap; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 核心优化3:修复解码参数,支持更多场景 | ||||
|      */ | ||||
|     private String decodeQrFromBitmap(Bitmap bitmap) { | ||||
|         if (bitmap == null) return null; | ||||
|  | ||||
|         try { | ||||
|             int width = bitmap.getWidth(); | ||||
|             int height = bitmap.getHeight(); | ||||
|             int[] pixels = new int[width * height]; | ||||
|             bitmap.getPixels(pixels, 0, width, 0, 0, width, height); | ||||
|  | ||||
|             // 修复1:使用RGBLuminanceSource,避免YUV格式导致的颜色偏差 | ||||
|             LuminanceSource source = new RGBLuminanceSource(width, height, pixels); | ||||
|             BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source)); | ||||
|  | ||||
|             // 修复2:完善解码参数,解决模糊、变形二维码识别问题 | ||||
|             Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(); | ||||
|             // 支持所有常见码制(不仅限于QR_CODE) | ||||
|             List<BarcodeFormat> formats = new ArrayList<BarcodeFormat>(); | ||||
|             formats.add(BarcodeFormat.QR_CODE); | ||||
|             formats.add(BarcodeFormat.CODE_128); | ||||
|             formats.add(BarcodeFormat.EAN_8); | ||||
|             formats.add(BarcodeFormat.EAN_13); | ||||
|             hints.put(DecodeHintType.POSSIBLE_FORMATS, formats); | ||||
|             // 字符编码:支持中文等多语言 | ||||
|             hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); | ||||
|             // 容错模式:允许二维码有一定损坏(关键!解决轻微变形/污染的二维码) | ||||
|             hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE); | ||||
|             // 不使用纯条码模式,兼容带logo的二维码 | ||||
|             hints.put(DecodeHintType.PURE_BARCODE, Boolean.FALSE); | ||||
|  | ||||
|             MultiFormatReader reader = new MultiFormatReader(); | ||||
|             reader.setHints(hints); | ||||
|             Result result = reader.decode(binaryBitmap); | ||||
|             return result.getText(); | ||||
|  | ||||
|         } catch (NotFoundException e) { | ||||
|             // 正常未识别到,不打印异常(避免日志冗余) | ||||
|             return null; | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // ==================== 原有逻辑(不变) ==================== | ||||
|     private void checkCameraPermission() { | ||||
|         if (checkSelfPermission(android.Manifest.permission.CAMERA) | ||||
| 			!= PackageManager.PERMISSION_GRANTED) { | ||||
|             requestPermissions(new String[]{android.Manifest.permission.CAMERA}, | ||||
| 							   REQUEST_CAMERA_PERMISSION); | ||||
|         } else { | ||||
|             startScanning(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void startScanning() { | ||||
|         barcodeView.decodeContinuous(barcodeCallback); | ||||
|     } | ||||
|  | ||||
|     private BarcodeCallback barcodeCallback = new BarcodeCallback() { | ||||
|         @Override | ||||
|         public void barcodeResult(BarcodeResult result) { | ||||
|             if (result.getText() != null) { | ||||
|                 //Toast.makeText(MainActivity.this, "Scanned: " + result.getText(), Toast.LENGTH_SHORT).show(); | ||||
|                 //ToastUtils.show("Scanned: " + result.getText()); | ||||
|             if (result != null && result.getText() != null) { | ||||
|                 barcodeView.pause(); | ||||
|                 Intent intent = new Intent(); | ||||
|                 intent.putExtra(EXTRA_RESULT, result.getText()); | ||||
|                 setResult(RESULT_OK, intent); | ||||
|                 finish(); | ||||
|                 String decodeResult = result.getText(); | ||||
|                 resultTextView.setText("扫码结果:" + decodeResult); | ||||
|                 showDecodeResultDialog(decodeResult); | ||||
|                 returnResultToPreviousPage(decodeResult); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -92,16 +326,111 @@ public class QRCodeDecodeActivity extends Activity { | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     private void showDecodeResultDialog(String result) { | ||||
|         ScrollView scrollView = new ScrollView(this); | ||||
|         scrollView.setPadding(dip2px(16), dip2px(16), dip2px(16), dip2px(16)); | ||||
|  | ||||
|         TextView dialogTv = new TextView(this); | ||||
|         dialogTv.setTextSize(16); | ||||
|         dialogTv.setTextColor(getResources().getColor(android.R.color.black)); | ||||
|         dialogTv.setText(result); | ||||
|         scrollView.addView(dialogTv); | ||||
|  | ||||
|         AlertDialog.Builder builder = new AlertDialog.Builder(this); | ||||
|         builder.setTitle("解码结果"); | ||||
|         builder.setView(scrollView); | ||||
|         builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(DialogInterface dialog, int which) { | ||||
| 					dialog.dismiss(); | ||||
| 					barcodeView.resume(); | ||||
| 				} | ||||
| 			}); | ||||
|         builder.setCancelable(false); | ||||
|         builder.show(); | ||||
|     } | ||||
|  | ||||
|     private void returnResultToPreviousPage(String result) { | ||||
|         Intent intent = new Intent(); | ||||
|         intent.putExtra(EXTRA_RESULT, result); | ||||
|         setResult(RESULT_OK, intent); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { | ||||
|         super.onRequestPermissionsResult(requestCode, permissions, grantResults); | ||||
|         if (requestCode == REQUEST_CAMERA_PERMISSION) { | ||||
|             if (grantResults != null && grantResults.length > 0) { | ||||
|                 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
|                     startScanning(); | ||||
|                 } else { | ||||
|                     new AlertDialog.Builder(this) | ||||
| 						.setTitle("权限申请") | ||||
| 						.setMessage("扫码需要相机权限,请在设置中开启") | ||||
| 						.setPositiveButton("确定", new DialogInterface.OnClickListener() { | ||||
| 							@Override | ||||
| 							public void onClick(DialogInterface dialog, int which) { | ||||
| 								dialog.dismiss(); | ||||
| 								finish(); | ||||
| 							} | ||||
| 						}) | ||||
| 						.setCancelable(false) | ||||
| 						.show(); | ||||
|                 } | ||||
|             } | ||||
|         } else if (requestCode == REQUEST_READ_STORAGE_PERMISSION) { | ||||
|             if (grantResults != null && grantResults.length > 0) { | ||||
|                 if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
|                     openAlbum(); | ||||
|                 } else { | ||||
|                     new AlertDialog.Builder(this) | ||||
| 						.setTitle("权限申请") | ||||
| 						.setMessage("从相册解码需要存储权限,请在设置中开启") | ||||
| 						.setPositiveButton("确定", new DialogInterface.OnClickListener() { | ||||
| 							@Override | ||||
| 							public void onClick(DialogInterface dialog, int which) { | ||||
| 								dialog.dismiss(); | ||||
| 							} | ||||
| 						}) | ||||
| 						.setCancelable(false) | ||||
| 						.show(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         barcodeView.resume(); | ||||
|         if (barcodeView != null) { | ||||
|             barcodeView.resume(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPause() { | ||||
|         super.onPause(); | ||||
|         barcodeView.pause(); | ||||
|         if (barcodeView != null) { | ||||
|             barcodeView.pause(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private int dip2px(float dpValue) { | ||||
|         final float scale = getResources().getDisplayMetrics().density; | ||||
|         return (int) (dpValue * scale + 0.5f); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(android.view.MenuItem item) { | ||||
|         if (item.getItemId() == android.R.id.home) { | ||||
|             finish(); | ||||
|             return true; | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     private void showToast(String message) { | ||||
|         android.widget.Toast.makeText(this, message, android.widget.Toast.LENGTH_SHORT).show(); | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,97 @@ | ||||
| package cc.winboll.studio.apputils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> | ||||
|  * @Date 2025/09/22 07:09 | ||||
|  * @Describe 二维码生成窗口 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.graphics.Bitmap; | ||||
| import android.os.Bundle; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.EditText; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.Toast; | ||||
| import com.google.zxing.BarcodeFormat; | ||||
| import com.google.zxing.WriterException; | ||||
| import com.journeyapps.barcodescanner.BarcodeEncoder; | ||||
|  | ||||
| public class QRGeneratorActivity extends Activity { | ||||
| 	public static final String TAG = "QrGeneratorActivity"; | ||||
|  | ||||
| 	// 控件引用 | ||||
| 	private EditText etInputText; | ||||
| 	private ImageView ivQrPreview; | ||||
| 	private Button btnGenerateQr; | ||||
|  | ||||
| 	@Override | ||||
| 	protected void onCreate(Bundle savedInstanceState) { | ||||
| 		super.onCreate(savedInstanceState); | ||||
| 		setContentView(R.layout.activity_qrgenerator); | ||||
|  | ||||
| 		// 初始化控件 | ||||
| 		initViews(); | ||||
| 		// 设置按钮点击事件 | ||||
| 		setGenerateClickListener(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 初始化布局控件 | ||||
| 	 */ | ||||
| 	private void initViews() { | ||||
| 		etInputText = findViewById(R.id.et_input_text); | ||||
| 		ivQrPreview = findViewById(R.id.iv_qr_preview); | ||||
| 		btnGenerateQr = findViewById(R.id.btn_generate_qr); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 设置生成按钮点击事件:获取输入文字 → 生成二维码 → 显示到 ImageView | ||||
| 	 */ | ||||
| 	private void setGenerateClickListener() { | ||||
| 		btnGenerateQr.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					// 1. 获取输入框文字(去除前后空格) | ||||
| 					String inputText = etInputText.getText().toString().trim(); | ||||
|  | ||||
| 					// 2. 空输入判断 | ||||
| 					if (inputText.isEmpty()) { | ||||
| 						Toast.makeText(QRGeneratorActivity.this, "请先输入要生成二维码的文字", Toast.LENGTH_SHORT).show(); | ||||
| 						return; | ||||
| 					} | ||||
|  | ||||
| 					// 3. 生成二维码 Bitmap(宽高 500px,可调整) | ||||
| 					Bitmap qrBitmap = generateQrCodeBitmap(inputText, 500, 500); | ||||
|  | ||||
| 					// 4. 显示二维码到 ImageView | ||||
| 					if (qrBitmap != null) { | ||||
| 						ivQrPreview.setImageBitmap(qrBitmap); | ||||
| 					} else { | ||||
| 						Toast.makeText(QRGeneratorActivity.this, "二维码生成失败,请重试", Toast.LENGTH_SHORT).show(); | ||||
| 					} | ||||
| 				} | ||||
| 			}); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 核心方法:生成二维码 Bitmap | ||||
| 	 * @param content 二维码内容(输入的文字) | ||||
| 	 * @param width 二维码宽度(px) | ||||
| 	 * @param height 二维码高度(px) | ||||
| 	 * @return 生成的二维码 Bitmap,失败返回 null | ||||
| 	 */ | ||||
| 	private Bitmap generateQrCodeBitmap(String content, int width, int height) { | ||||
| 		try { | ||||
| 			// 初始化二维码编码器(指定格式为 QR_CODE) | ||||
| 			BarcodeEncoder encoder = new BarcodeEncoder(); | ||||
| 			// 生成二维码 Bitmap(参数:内容、格式、宽、高) | ||||
| 			return encoder.encodeBitmap(content, BarcodeFormat.QR_CODE, width, height); | ||||
| 		} catch (WriterException e) { | ||||
| 			// 生成失败(如内容过长、宽高非法),打印异常信息 | ||||
| 			e.printStackTrace(); | ||||
| 			return null; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -1,7 +1,7 @@ | ||||
| package cc.winboll.studio.apputils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/03/23 16:14:45 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
|   | ||||
| @@ -1,36 +0,0 @@ | ||||
| package cc.winboll.studio.apputils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2025/01/17 19:50:46 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.apputils.R; | ||||
| import cc.winboll.studio.libapputils.views.StringToQrCodeView; | ||||
|  | ||||
| public class TestStringToQRCodeViewActivity extends Activity { | ||||
|  | ||||
|     public static final String TAG = "TestStringToQrCodeViewActivity"; | ||||
|  | ||||
|     StringToQrCodeView mStringToQrCodeView; | ||||
| // | ||||
| //    @Override | ||||
| //    public Activity getActivity() { | ||||
| //        return this; | ||||
| //    } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_teststringtoqrcodeview); | ||||
|          | ||||
|         // 初始化工具栏 | ||||
|         Toolbar mToolbar = findViewById(R.id.toolbar); | ||||
|         mToolbar.setSubtitle(TAG); | ||||
|         setActionBar(mToolbar); | ||||
|          | ||||
|         mStringToQrCodeView = findViewById(R.id.activityteststringtoqrcodeviewStringToQrCodeView1); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,14 @@ | ||||
| package cc.winboll.studio.apputils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/05/13 11:15 | ||||
|  * @Describe WinBoLLActivity | ||||
|  */ | ||||
| import android.app.Activity; | ||||
|  | ||||
| public class WinBoLLActivity extends Activity { | ||||
|  | ||||
|     public static final String TAG = "WinBoLLActivity"; | ||||
|  | ||||
| } | ||||
| @@ -1,51 +0,0 @@ | ||||
| package cc.winboll.studio.apputils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/03/28 17:11:37 | ||||
|  * @Describe 应用活动窗口基类 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.os.Bundle; | ||||
| import android.os.PersistableBundle; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.IWinBollActivity; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBollActivityManager; | ||||
|  | ||||
| public class WinBollActivityBase extends Activity implements IWinBollActivity { | ||||
|  | ||||
|     public static final String TAG = "WinBollActivityBase"; | ||||
|  | ||||
|     @Override | ||||
|     public Activity getActivity() { | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     WinBollActivityManager getWinBollActivityManager() { | ||||
|         return WinBollActivityManager.getInstance(GlobalApplication.getInstance()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         getWinBollActivityManager().add(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) { | ||||
|         super.onPostCreate(savedInstanceState, persistentState); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         getWinBollActivityManager().registeRemove(this); | ||||
|     } | ||||
| } | ||||
| @@ -54,13 +54,6 @@ | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<cc.winboll.studio.libappbase.LogView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="0dp" | ||||
| 			android:text="Button" | ||||
| 			android:id="@+id/logview" | ||||
| 			android:layout_weight="1.0"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|   | ||||
| @@ -1,20 +1,43 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| <LinearLayout  | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:orientation="vertical" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent"> | ||||
|     android:layout_height="match_parent" | ||||
|     android:orientation="vertical"> | ||||
|  | ||||
|     <TextView | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="QRCodeDecodeActivity"/> | ||||
|     <!-- 工具栏(原有) --> | ||||
|     <Toolbar | ||||
|         android:id="@+id/toolbar" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content"/> | ||||
|  | ||||
|     <!-- 扫码控件(原有) --> | ||||
|     <com.journeyapps.barcodescanner.DecoratedBarcodeView | ||||
|         android:layout_width="wrap_content" | ||||
|         android:id="@+id/activityqrcodedecodeDecoratedBarcodeView1" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="0dp" | ||||
|         android:layout_weight="1"/> | ||||
|  | ||||
|     <!-- 新增:从相册解码按钮 --> | ||||
|     <Button | ||||
|         android:id="@+id/btn_decode_from_album" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:id="@+id/activityqrcodedecodeDecoratedBarcodeView1"/> | ||||
|         android:text="从相册选图解码" | ||||
|         android:textSize="16sp" | ||||
|         android:textColor="@android:color/white" | ||||
|         android:background="#2196F3" | ||||
|         android:paddingVertical="12dp" | ||||
|         android:layout_margin="16dp"/> | ||||
|  | ||||
|     <!-- 结果显示TextView(原有) --> | ||||
|     <TextView | ||||
|         android:id="@+id/activityqrcodedecodeTextView1" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:padding="16dp" | ||||
|         android:text="等待扫码或选择图片..." | ||||
|         android:textSize="16sp"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
|   | ||||
							
								
								
									
										45
									
								
								apputils/src/main/res/layout/activity_qrgenerator.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								apputils/src/main/res/layout/activity_qrgenerator.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:orientation="vertical" | ||||
|     android:padding="20dp" | ||||
|     android:gravity="top|center_horizontal"> | ||||
|  | ||||
|     <!-- 文字输入框 --> | ||||
|     <EditText | ||||
|         android:id="@+id/et_input_text" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:hint="请输入要生成二维码的文字" | ||||
|         android:inputType="textMultiLine" | ||||
|         android:minLines="3" | ||||
|         android:maxLines="5" | ||||
|         android:padding="12dp" | ||||
|         android:background="@android:drawable/editbox_background_normal" | ||||
|         android:layout_marginBottom="16dp"/> | ||||
|  | ||||
|     <!-- 生成二维码按钮 --> | ||||
|     <Button | ||||
|         android:id="@+id/btn_generate_qr" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="生成二维码" | ||||
|         android:textSize="16sp" | ||||
|         android:background="#4CAF50" | ||||
|         android:textColor="@android:color/white" | ||||
|         android:paddingVertical="12dp" | ||||
|         android:layout_marginBottom="24dp"/> | ||||
|  | ||||
|     <!-- 二维码预览图片 --> | ||||
|     <ImageView | ||||
|         android:id="@+id/iv_qr_preview" | ||||
|         android:layout_width="280dp" | ||||
|         android:layout_height="280dp" | ||||
|         android:scaleType="fitCenter" | ||||
|         android:background="@android:drawable/dialog_holo_light_frame" | ||||
|         android:contentDescription="二维码预览"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -2,8 +2,8 @@ | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|     <item | ||||
|         android:id="@+id/item_teststringtoqrcodeview" | ||||
|         android:title="TestStringToQRCodeViewActivity"/> | ||||
|         android:id="@+id/item_testqrgeneratoractivity" | ||||
|         android:title="TestQRGeneratorActivity"/> | ||||
|     <item | ||||
|         android:id="@+id/item_testqrcodedecodeactivity" | ||||
|         android:title="TestQRCodeDecodeActivity"/> | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <!-- WinBoll 默认方案 --> | ||||
|     <!-- WinBoLL 默认方案 --> | ||||
|     <color name="colorPrimary">#FF196ABC</color> | ||||
|     <color name="colorPrimaryDark">#FF002B57</color> | ||||
|     <color name="colorAccent">#FF80BFFF</color> | ||||
|   | ||||
							
								
								
									
										35
									
								
								autoinstaller/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								autoinstaller/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| # AutoInstaller | ||||
|  | ||||
| #### 介绍 | ||||
| APK 文件监控,监控指定文件路径的 APK 文件。 | ||||
| 在 APK 文件改变后自动调用系统安装命令安装,或者调用[应用信息查看器]打开。 | ||||
|  | ||||
| #### 软件架构 | ||||
| 适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。 | ||||
| 也适配安卓应用 [AndroidIDE] 的 Gradle 编译结构。 | ||||
|  | ||||
|  | ||||
| #### Gradle 编译说明 | ||||
| 调试版编译命令 :gradle assembleBetaDebug | ||||
| 阶段版编译命令 :bash .winboll/bashPublishAPKAddTag.sh autoinstaller | ||||
|  | ||||
| #### 使用说明 | ||||
|  | ||||
| #### 参与贡献 | ||||
|  | ||||
| 1.  Fork 本仓库 | ||||
| 2.  新建 Feat_xxx 分支 | ||||
| 3.  提交代码 : ZhanGSKen(ZhanGSKen<zhangsken@188.com>) | ||||
| 4.  新建 Pull Request | ||||
|  | ||||
|  | ||||
| #### 特技 | ||||
|  | ||||
| 1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md | ||||
| 2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) | ||||
| 3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 | ||||
| 4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 | ||||
| 5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) | ||||
| 6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) | ||||
|  | ||||
| #### 参考文档 | ||||
| @@ -19,7 +19,7 @@ def genVersionName(def versionName){ | ||||
|  | ||||
| android { | ||||
|     compileSdkVersion 32 | ||||
|     buildToolsVersion "33.0.3" | ||||
|     buildToolsVersion "32.0.0" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.autoinstaller" | ||||
| @@ -29,7 +29,7 @@ android { | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "5.0"  | ||||
|         versionName "15.2"  | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
| @@ -41,30 +41,33 @@ android { | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     compileOptions { | ||||
|         sourceCompatibility JavaVersion.VERSION_11 | ||||
|         targetCompatibility JavaVersion.VERSION_11 | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
| 	api 'cc.winboll.studio:winboll-shared:1.1.0' | ||||
|     api 'io.github.medyo:android-about-page:2.0.0' | ||||
|     api 'com.github.getActivity:ToastUtils:10.5' | ||||
|     api 'com.jcraft:jsch:0.1.55' | ||||
|     api 'org.jsoup:jsoup:1.13.1' | ||||
|     api 'com.squareup.okhttp3:okhttp:4.4.1' | ||||
|      | ||||
|     api 'androidx.appcompat:appcompat:1.0.0' | ||||
|     api 'androidx.fragment:fragment:1.0.0' | ||||
|     api 'com.google.android.material:material:1.0.0' | ||||
|      | ||||
|     api 'androidx.vectordrawable:vectordrawable-animated:1.0.0' | ||||
|     api 'androidx.lifecycle:lifecycle-livedata:1.0.0' | ||||
|      | ||||
|     //api 'cc.winboll.studio:libaes:6.3.2' | ||||
|     //api 'cc.winboll.studio:libapputils:8.3.8' | ||||
|      | ||||
|     api fileTree(dir: 'libs', include: ['*.jar']) | ||||
|     api 'cc.winboll.studio:libaes:15.6.0' | ||||
|     api 'cc.winboll.studio:libapputils:15.3.4' | ||||
|     api 'cc.winboll.studio:libappbase:15.7.6' | ||||
|      | ||||
|     // SSH | ||||
|     api 'com.jcraft:jsch:0.1.55' | ||||
|     // Html 解析 | ||||
|     api 'org.jsoup:jsoup:1.13.1' | ||||
|     // 二维码类库 | ||||
|     api 'com.google.zxing:core:3.4.1' | ||||
|     api 'com.journeyapps:zxing-android-embedded:3.6.0' | ||||
|     // 应用介绍页类库 | ||||
|     api 'io.github.medyo:android-about-page:2.0.0' | ||||
|     // 吐司类库 | ||||
|     api 'com.github.getActivity:ToastUtils:10.5' | ||||
|     // 网络连接类库 | ||||
|     api 'com.squareup.okhttp3:okhttp:4.4.1' | ||||
|     // AndroidX 类库 | ||||
|     api 'androidx.appcompat:appcompat:1.1.0' | ||||
|     api 'com.google.android.material:material:1.4.0' | ||||
|     //api 'androidx.viewpager:viewpager:1.0.0' | ||||
|     //api 'androidx.vectordrawable:vectordrawable:1.1.0' | ||||
|     //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0' | ||||
|     //api 'androidx.fragment:fragment:1.1.0' | ||||
|      | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Thu Jan 02 02:39:56 HKT 2025 | ||||
| stageCount=4 | ||||
| #Tue Jun 24 09:54:47 HKT 2025 | ||||
| stageCount=3 | ||||
| libraryProject= | ||||
| baseVersion=5.0 | ||||
| publishVersion=5.0.3 | ||||
| baseVersion=15.2 | ||||
| publishVersion=15.2.2 | ||||
| buildCount=0 | ||||
| baseBetaVersion=5.0.4 | ||||
| baseBetaVersion=15.2.3 | ||||
|   | ||||
| @@ -23,6 +23,8 @@ | ||||
|  | ||||
|     <!-- MANAGE_EXTERNAL_STORAGE --> | ||||
|     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> | ||||
|          | ||||
|     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> | ||||
|  | ||||
|     <application | ||||
|         android:name=".App" | ||||
| @@ -33,7 +35,7 @@ | ||||
|         android:persistent="true" | ||||
|         android:supportsRtl="true" | ||||
|         android:requestLegacyExternalStorage="true" | ||||
|         android:theme="@style/Theme.Application"> | ||||
|         android:theme="@style/MyAppTheme"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
| @@ -54,6 +56,21 @@ | ||||
|  | ||||
|         <service android:name=".services.AssistantService"/> | ||||
|  | ||||
|         <service | ||||
|             android:name=".AppBaseTileService" | ||||
|             android:exported="true" | ||||
|             android:label="@string/tileservice_name" | ||||
|             android:icon="@drawable/ic_launcher" | ||||
|             android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.service.quicksettings.action.QS_TILE"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </service> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".receivers.MainReceiver" | ||||
|             android:enabled="true" | ||||
|   | ||||
| @@ -1,27 +1,28 @@ | ||||
| package cc.winboll.studio.autoinstaller; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/04/28 02:39:58 | ||||
|  * @Describe 全局应用类 | ||||
|  */ | ||||
| import android.view.Gravity; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import cc.winboll.studio.shared.app.WinBollApplication; | ||||
| import com.hjq.toast.style.WhiteToastStyle; | ||||
|  | ||||
| public class App extends WinBollApplication { | ||||
| public class App extends GlobalApplication { | ||||
|      | ||||
|     public static final String TAG = "App"; | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         setIsDebug(BuildConfig.DEBUG); | ||||
|          | ||||
|         // 初始化 Toast 框架 | ||||
|         ToastUtils.init(this); | ||||
|         // 设置 Toast 布局样式 | ||||
|         ToastUtils.setView(R.layout.toast_custom_view); | ||||
|         //ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         //ToastUtils.setView(R.layout.view_toast); | ||||
|         ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         ToastUtils.setGravity(Gravity.BOTTOM, 0, 200); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,12 @@ | ||||
| package cc.winboll.studio.autoinstaller; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/04/15 09:24:46 | ||||
|  * @Describe 磁贴工具服务类 | ||||
|  */ | ||||
| import android.service.quicksettings.Tile; | ||||
| import android.service.quicksettings.TileService; | ||||
| import cc.winboll.studio.autoinstaller.models.AppConfigs; | ||||
|  | ||||
|  | ||||
| @@ -1,7 +1,7 @@ | ||||
| package cc.winboll.studio.autoinstaller; | ||||
|  | ||||
| import android.os.FileObserver; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| public class FileListener extends FileObserver { | ||||
| 	public final static String TAG = "FileListener"; | ||||
|   | ||||
| @@ -6,21 +6,24 @@ import android.graphics.Color; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Message; | ||||
| import android.view.View; | ||||
| import android.widget.EditText; | ||||
| import android.widget.RadioButton; | ||||
| import android.widget.SimpleAdapter; | ||||
| import android.widget.Switch; | ||||
| import android.widget.TextClock; | ||||
| import android.widget.Toast; | ||||
| import androidx.core.content.FileProvider; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import cc.winboll.studio.shared.log.LogView; | ||||
| import cc.winboll.studio.autoinstaller.MainActivity; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.models.APKModel; | ||||
| import cc.winboll.studio.autoinstaller.models.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.services.MainService; | ||||
| import cc.winboll.studio.autoinstaller.utils.NotificationUtil; | ||||
| import cc.winboll.studio.autoinstaller.utils.PackageUtil; | ||||
| import cc.winboll.studio.autoinstaller.views.ListViewForScrollView; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import cc.winboll.studio.libappbase.LogView; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.io.File; | ||||
| import java.util.ArrayList; | ||||
| @@ -30,8 +33,13 @@ import java.util.Map; | ||||
| public class MainActivity extends Activity { | ||||
|     public static final String TAG = "MainActivity"; | ||||
|  | ||||
|     public static final int MSG_UPDATE_STATUS = 0; | ||||
|  | ||||
|     private static final int INSTALL_PERMISSION_CODE = 1; | ||||
|  | ||||
|     static MainActivity _MainActivity; | ||||
|  | ||||
|     ArrayList<APKModel> _APKModelList = new ArrayList<APKModel>(); | ||||
|     LogView mLogView; | ||||
|     TextClock mTextClock; | ||||
|     EditText mEditText; | ||||
| @@ -60,9 +68,11 @@ public class MainActivity extends Activity { | ||||
|  | ||||
|         super.onCreate(savedInstanceState); | ||||
| 		setContentView(R.layout.activity_main); | ||||
|         _MainActivity = this; | ||||
|         initView(); | ||||
|  | ||||
|         if (getIntent().getAction().equals(ACTION_NEW_INSTALLTASK)) { | ||||
|         String action = getIntent().getAction(); | ||||
|         if ((action != null) && action.equals(ACTION_NEW_INSTALLTASK)) { | ||||
|             mszInstalledPackageName = getIntent().getStringExtra(EXTRA_INSTALLED_PACKAGENAME); | ||||
|             mszInstalledAPKFilePath = getIntent().getStringExtra(EXTRA_INSTALLED_APKFILEPATH); | ||||
|             installAPK(); | ||||
| @@ -76,11 +86,7 @@ public class MainActivity extends Activity { | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|         mLogView.start(); | ||||
|  | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(this); | ||||
|         if (appConfigs == null) { | ||||
|             appConfigs = new AppConfigs();  | ||||
|             AppConfigs.saveAppConfigs(this, appConfigs); | ||||
|         } | ||||
|         AppConfigs appConfigs = AppConfigs.getInstance(this).loadAppConfigs(this); | ||||
|  | ||||
|         if (appConfigs.getSetupMode() == AppConfigs.SetupMode.WATCHOUTPUTINSTALLER) { | ||||
|             ((RadioButton)findViewById(R.id.activitymainRadioButton1)).setChecked(true); | ||||
| @@ -131,23 +137,44 @@ public class MainActivity extends Activity { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     String getLastApkPackageName() { | ||||
|         APKModel.loadBeanList(this, _APKModelList, APKModel.class); | ||||
|         if (_APKModelList.size() > 0) { | ||||
|             return _APKModelList.get(_APKModelList.size() - 1).getApkPackageName(); | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     public void onOpenAPP(View view) { | ||||
|         if (mszInstalledPackageName.trim().equals("")) { | ||||
|         String szInstalledPackageName = getLastApkPackageName(); | ||||
|         LogUtils.d(TAG, "szInstalledPackageName : " + szInstalledPackageName); | ||||
|         if (szInstalledPackageName.trim().equals("")) { | ||||
|             ToastUtils.show("Installed APP package name is null."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Intent intent = getPackageManager().getLaunchIntentForPackage(mszInstalledPackageName); | ||||
|         if (intent != null) { | ||||
|             startActivity(intent); | ||||
|         } else { | ||||
|             // 若没能获取到启动意图,可进行相应提示等操作,比如跳转到应用商店让用户下载该应用(示例) | ||||
|             Intent marketIntent = new Intent(Intent.ACTION_VIEW); | ||||
|             marketIntent.setData(Uri.parse("market://details?id=" + mszInstalledPackageName)); | ||||
|             startActivity(marketIntent); | ||||
|         } | ||||
|         PackageUtil.openAPP(this, szInstalledPackageName); | ||||
|     } | ||||
|  | ||||
| //    public void onOpenAPP(View view) { | ||||
| //        String szInstalledPackageName = getLastApkPackageName(); | ||||
| //        if (szInstalledPackageName.trim().equals("")) { | ||||
| //            ToastUtils.show("Installed APP package name is null."); | ||||
| //            return; | ||||
| //        } | ||||
| // | ||||
| //        Intent intent = getPackageManager().getLaunchIntentForPackage(mszInstalledPackageName); | ||||
| //        if (intent != null) { | ||||
| //            //ToastUtils.show("startActivity"); | ||||
| //            startActivity(intent); | ||||
| //        } else { | ||||
| //            // 若没能获取到启动意图,可进行相应提示等操作,比如跳转到应用商店让用户下载该应用(示例) | ||||
| //            Intent marketIntent = new Intent(Intent.ACTION_VIEW); | ||||
| //            marketIntent.setData(Uri.parse("market://details?id=" + mszInstalledPackageName)); | ||||
| //            startActivity(marketIntent); | ||||
| //        } | ||||
| //    } | ||||
|  | ||||
|     public void onInstallAPK(View view) { | ||||
|         installAPK(); | ||||
|     } | ||||
| @@ -185,17 +212,22 @@ public class MainActivity extends Activity { | ||||
|     } | ||||
|  | ||||
|     public void onLockPath(View view) { | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(this); | ||||
|  | ||||
|         Switch sw = (Switch)view; | ||||
|         if (sw.isChecked()) { | ||||
|         setMainServiceStatus(sw.isChecked()); | ||||
|     } | ||||
|  | ||||
|     public void setMainServiceStatus(boolean isEnable) { | ||||
|         AppConfigs appConfigs = AppConfigs.getInstance(this).loadAppConfigs(this); | ||||
|  | ||||
|         Switch sw = (Switch)findViewById(R.id.activitymainSwitch1); | ||||
|         if (isEnable) { | ||||
|             String szFilePath = mEditText.getText().toString(); | ||||
|  | ||||
|             // 设置空路径时退出 | ||||
|             // | ||||
|             if (szFilePath.trim().equals("")) { | ||||
|                 sw.setChecked(false); | ||||
|                 Toast.makeText(getApplication(), "监控路径为空。", Toast.LENGTH_SHORT).show(); | ||||
|                 ToastUtils.show("监控路径为空。"); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
| @@ -236,7 +268,7 @@ public class MainActivity extends Activity { | ||||
|             stopWatchingFile(); | ||||
|  | ||||
|         } | ||||
|         AppConfigs.saveAppConfigs(this, appConfigs); | ||||
|         AppConfigs.getInstance(this).saveAppConfigs(this, appConfigs); | ||||
|     } | ||||
|  | ||||
|     void stopWatchingFile() { | ||||
| @@ -251,8 +283,6 @@ public class MainActivity extends Activity { | ||||
|         Intent intentService = new Intent(MainActivity.this, MainService.class); | ||||
|         //intentService.putExtra(MainService.EXTRA_APKFILEPATH, szAPKFilePath); | ||||
|         startService(intentService); | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /* | ||||
| @@ -298,7 +328,7 @@ public class MainActivity extends Activity { | ||||
|      }*/ | ||||
|  | ||||
|     public void onChangeSetupMode(View view) { | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(this); | ||||
|         AppConfigs appConfigs = AppConfigs.getInstance(this).loadAppConfigs(this); | ||||
|  | ||||
|         if (view.getId() == R.id.activitymainRadioButton1) { | ||||
|             appConfigs.setSetupMode(AppConfigs.SetupMode.WATCHOUTPUTINSTALLER); | ||||
| @@ -307,6 +337,42 @@ public class MainActivity extends Activity { | ||||
|             appConfigs.setSetupMode(AppConfigs.SetupMode.NEWAPKINFONEWAPKINFO); | ||||
|             ((RadioButton)findViewById(R.id.activitymainRadioButton1)).setChecked(false); | ||||
|         } | ||||
|         AppConfigs.saveAppConfigs(this, appConfigs); | ||||
|         AppConfigs.getInstance(this).saveAppConfigs(this, appConfigs); | ||||
|     } | ||||
|  | ||||
|     // 定义Handler | ||||
|     static Handler _Handler = new Handler() { | ||||
|         @Override | ||||
|         public void handleMessage(Message msg) { | ||||
|             super.handleMessage(msg); | ||||
|             if (msg.what == MSG_UPDATE_STATUS) { | ||||
|                 if (_MainActivity != null) { | ||||
|                     boolean isEnableMainService = (boolean)msg.obj; | ||||
|                     // 处理消息,这里更新 MainService 的状态 | ||||
|                     _MainActivity.setMainServiceStatus(isEnableMainService); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     static void updateMainServiceStatus(boolean isEnable) { | ||||
|         if (_Handler != null) { | ||||
|             Message msg = new Message(); | ||||
|             msg.obj = isEnable; | ||||
|             msg.what = MSG_UPDATE_STATUS; | ||||
|             _Handler.sendMessage(msg); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void stopMainService() { | ||||
|         if (_MainActivity != null && _Handler != null) { | ||||
|             updateMainServiceStatus(false); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void startMainService() { | ||||
|         if (_MainActivity != null && _Handler != null) { | ||||
|             updateMainServiceStatus(true); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,54 +1,57 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
| package cc.winboll.studio.autoinstaller.models; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/17 10:05:09 | ||||
|  * @Describe APPSOSReportBean | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/04/02 20:50:29 | ||||
|  * @Describe 监控的 APK 安装文件对应的应用信息数据模型 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| public class WinBollNewsBean extends BaseBean { | ||||
|      | ||||
|     public static final String TAG = "WinBollNewsBean"; | ||||
|      | ||||
|     protected String message; | ||||
|      | ||||
|     public WinBollNewsBean() { | ||||
|         this.message = ""; | ||||
| public class APKModel extends BaseBean { | ||||
| 
 | ||||
|     public static final String TAG = "APPModel"; | ||||
| 
 | ||||
|     // 每次更新的 APK 文件对应的应用包名称 | ||||
|     String apkPackageName; | ||||
| 
 | ||||
|     public APKModel() { | ||||
|         this.apkPackageName = ""; | ||||
|     } | ||||
| 
 | ||||
|     public WinBollNewsBean(String message) { | ||||
|         this.message = message; | ||||
|     public APKModel(String apkPackageName) { | ||||
|         this.apkPackageName = apkPackageName; | ||||
|     } | ||||
| 
 | ||||
|     public void setMessage(String message) { | ||||
|         this.message = message; | ||||
|     public void setApkPackageName(String apkPackageName) { | ||||
|         this.apkPackageName = apkPackageName; | ||||
|     } | ||||
| 
 | ||||
|     public String getMessage() { | ||||
|         return message; | ||||
|     public String getApkPackageName() { | ||||
|         return apkPackageName; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return WinBollNewsBean.class.getName(); | ||||
|         return APKModel.class.getName(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         jsonWriter.name("message").value(getMessage()); | ||||
|         jsonWriter.name("appPackageName").value(getApkPackageName()); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { | ||||
|             if (name.equals("message")) { | ||||
|                 setMessage(jsonReader.nextString()); | ||||
|             if (name.equals("appPackageName")) { | ||||
|                 setApkPackageName(jsonReader.nextString()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
| @@ -1,20 +1,21 @@ | ||||
| package cc.winboll.studio.autoinstaller.beans; | ||||
| package cc.winboll.studio.autoinstaller.models; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/05/27 17:36:01 | ||||
|  * @Describe 应用配置数据类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.models.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.utils.FileUtil; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.io.IOException; | ||||
| import java.io.Serializable; | ||||
| import java.io.StringReader; | ||||
| import java.io.StringWriter; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| 
 | ||||
| public class AppConfigs implements Serializable { | ||||
| 
 | ||||
| @@ -26,6 +27,21 @@ public class AppConfigs implements Serializable { | ||||
|         NEWAPKINFONEWAPKINFO  // 调用[应用信息查看器]打开应用包 | ||||
|         }; | ||||
| 
 | ||||
|     static volatile AppConfigs _AppConfigs; | ||||
|     Context mContext; | ||||
| 
 | ||||
|     AppConfigs(Context context) { | ||||
|         mContext = context.getApplicationContext(); | ||||
|     } | ||||
| 
 | ||||
|     public static synchronized AppConfigs getInstance(Context context) { | ||||
|         if (_AppConfigs == null) { | ||||
|             _AppConfigs = new AppConfigs(context); | ||||
|             _AppConfigs.loadAppConfigs(_AppConfigs.mContext); | ||||
|         } | ||||
|         return _AppConfigs; | ||||
|     } | ||||
| 
 | ||||
|     // 监控文件路径 | ||||
|     private String watchingFilePath = ""; | ||||
| 
 | ||||
| @@ -85,8 +101,8 @@ public class AppConfigs implements Serializable { | ||||
|         return ""; | ||||
|     } | ||||
| 
 | ||||
|     public static AppConfigs parseAppConfigs(String szAppConfigs) { | ||||
|         AppConfigs appConfigs = new AppConfigs(); | ||||
|     public AppConfigs parseAppConfigs(String szAppConfigs) { | ||||
|         AppConfigs appConfigs = new AppConfigs(mContext); | ||||
|         // 创建 JsonWriter 对象 | ||||
|         StringReader stringReader = new StringReader(szAppConfigs); | ||||
|         JsonReader jsonReader = new | ||||
| @@ -121,20 +137,35 @@ public class AppConfigs implements Serializable { | ||||
|     static String getDataPath(Context context) { | ||||
|         return context.getExternalFilesDir(TAG) + "/" + TAG + ".json"; | ||||
|     } | ||||
| 
 | ||||
|     public static AppConfigs loadAppConfigs(Context context) { | ||||
|      | ||||
|     public AppConfigs loadAppConfigs() { | ||||
|         AppConfigs appConfigs = null; | ||||
|         try { | ||||
|             String szJson = FileUtil.readFile(getDataPath(context)); | ||||
|             appConfigs = AppConfigs.parseAppConfigs(szJson); | ||||
|             String szJson = FileUtil.readFile(getDataPath(mContext)); | ||||
|             appConfigs = AppConfigs.getInstance(mContext).parseAppConfigs(szJson); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return appConfigs; | ||||
|     } | ||||
| 
 | ||||
|     public static void saveAppConfigs(Context context, AppConfigs appConfigs) { | ||||
|     public AppConfigs loadAppConfigs(Context context) { | ||||
|         AppConfigs appConfigs = null; | ||||
|         try { | ||||
|             String szJson = FileUtil.readFile(getDataPath(context.getApplicationContext())); | ||||
|             appConfigs = AppConfigs.getInstance(mContext).parseAppConfigs(szJson); | ||||
|             if(appConfigs != null) { | ||||
|                 _AppConfigs = appConfigs; | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return _AppConfigs; | ||||
|     } | ||||
| 
 | ||||
|     public void saveAppConfigs(Context context, AppConfigs appConfigs) { | ||||
|         try { | ||||
|             ToastUtils.show(String.format("AppConfigs set enable service to %s", appConfigs.isEnableService())); | ||||
|             //LogUtils.d(TAG, "appConfigs is : " + appConfigs.toString()); | ||||
|             String szJson = appConfigs.toString(); | ||||
|             FileUtil.writeFile(getDataPath(context), szJson); | ||||
| @@ -142,4 +173,8 @@ public class AppConfigs implements Serializable { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void saveAppConfigs() { | ||||
|         saveAppConfigs(mContext, this); | ||||
|     } | ||||
| } | ||||
| @@ -1,14 +1,14 @@ | ||||
| package cc.winboll.studio.appbase.models; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen@AliYun.Com | ||||
|  * @Date 2025/02/13 07:06:13 | ||||
|  */ | ||||
| package cc.winboll.studio.autoinstaller.models; | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.libappbase.BaseBean; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| /** | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2025/04/15 09:27:39 | ||||
|  * @Describe MainServiceBean | ||||
|  */ | ||||
| public class MainServiceBean extends BaseBean { | ||||
| 
 | ||||
|     public static final String TAG = "MainServiceBean"; | ||||
| @@ -4,12 +4,12 @@ import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Build; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.models.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.services.MainService; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/06/06 13:19:38 | ||||
|  * @Describe 应用消息接收类 | ||||
|  */ | ||||
| @@ -23,7 +23,7 @@ public class MainReceiver extends BroadcastReceiver { | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String szAction = intent.getAction(); | ||||
|         if (szAction.equals(ACTION_BOOT_COMPLETED)) { | ||||
|             AppConfigs appConfigs = AppConfigs.loadAppConfigs(context); | ||||
|             AppConfigs appConfigs = AppConfigs.getInstance(context).loadAppConfigs(context); | ||||
|             if (appConfigs.isEnableService()) { | ||||
|                 Intent intentService = new Intent(context, MainService.class); | ||||
|                 //intentService.putExtra(MainService.EXTRA_APKFILEPATH, appConfigs.getWatchingFilePath()); | ||||
|   | ||||
| @@ -6,11 +6,11 @@ import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.models.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.utils.ServiceUtil; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/05/27 20:16:00 | ||||
|  * @Describe MainService 守护进程服务 | ||||
|  */ | ||||
| @@ -46,7 +46,7 @@ public class AssistantService extends Service { | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         //LogUtils.d(TAG, "call onStartCommand(...)"); | ||||
|         run(); | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(AssistantService.this); | ||||
|         AppConfigs appConfigs = AppConfigs.getInstance(AssistantService.this).loadAppConfigs(AssistantService.this); | ||||
|         return appConfigs.isEnableService() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
| @@ -68,7 +68,7 @@ public class AssistantService extends Service { | ||||
|     // | ||||
|     void run() { | ||||
|         //LogUtils.d(TAG, "call run()"); | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(AssistantService.this); | ||||
|         AppConfigs appConfigs = AppConfigs.getInstance(AssistantService.this).loadAppConfigs(AssistantService.this); | ||||
|         if (appConfigs.isEnableService()) { | ||||
|             if (mIsThreadAlive == false) { | ||||
|                 // 设置运行状态 | ||||
| @@ -101,7 +101,7 @@ public class AssistantService extends Service { | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             //LogUtils.d(TAG, "call onServiceDisconnected(...)"); | ||||
|             AppConfigs appConfigs = AppConfigs.loadAppConfigs(AssistantService.this); | ||||
|             AppConfigs appConfigs = AppConfigs.getInstance(AssistantService.this).loadAppConfigs(AssistantService.this); | ||||
|             if (appConfigs.isEnableService()) { | ||||
|                 wakeupAndBindMain(); | ||||
|             } | ||||
|   | ||||
| @@ -10,25 +10,32 @@ import android.os.Build; | ||||
| import android.os.Handler; | ||||
| import android.os.IBinder; | ||||
| import android.os.Message; | ||||
| import android.service.quicksettings.Tile; | ||||
| import android.service.quicksettings.TileService; | ||||
| import android.widget.Toast; | ||||
| import androidx.core.content.FileProvider; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import cc.winboll.studio.autoinstaller.FileListener; | ||||
| import cc.winboll.studio.autoinstaller.MainActivity; | ||||
| import cc.winboll.studio.autoinstaller.beans.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.R; | ||||
| import cc.winboll.studio.autoinstaller.models.APKModel; | ||||
| import cc.winboll.studio.autoinstaller.models.AppConfigs; | ||||
| import cc.winboll.studio.autoinstaller.services.AssistantService; | ||||
| import cc.winboll.studio.autoinstaller.services.MainService; | ||||
| import cc.winboll.studio.autoinstaller.utils.NotificationUtil; | ||||
| import cc.winboll.studio.autoinstaller.utils.PackageUtil; | ||||
| import cc.winboll.studio.autoinstaller.utils.ServiceUtil; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
| import java.io.File; | ||||
| import java.lang.ref.WeakReference; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class MainService extends Service { | ||||
|  | ||||
|     public static String TAG = "MainService"; | ||||
|      | ||||
|     Context mContext; | ||||
|  | ||||
|     ArrayList<APKModel> _APKModelList = new ArrayList<APKModel>(); | ||||
|     private static boolean _mIsServiceAlive; | ||||
|     //String mszAPKFilePath; | ||||
|     //String mszAPKFileName; | ||||
| @@ -47,6 +54,7 @@ public class MainService extends Service { | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         mContext = this; | ||||
|         LogUtils.d(TAG, "onCreate()"); | ||||
|         _mIsServiceAlive = false; | ||||
|         mHandler = new MyHandler(MainService.this); | ||||
| @@ -55,11 +63,14 @@ public class MainService extends Service { | ||||
|         } | ||||
|  | ||||
|         run(); | ||||
|          | ||||
|         // 初始化磁贴工具服务 | ||||
|         MainTileService mainTileService = new MainTileService(this); | ||||
|     } | ||||
|  | ||||
|     private void run() { | ||||
|  | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(MainService.this); | ||||
|         AppConfigs appConfigs = AppConfigs.getInstance(MainService.this).loadAppConfigs(MainService.this); | ||||
|         if (appConfigs.isEnableService()) { | ||||
|             if (_mIsServiceAlive == false) { | ||||
|                 // 设置运行状态 | ||||
| @@ -74,7 +85,8 @@ public class MainService extends Service { | ||||
|  | ||||
|                 startWatchingFile(appConfigs.getWatchingFilePath()); | ||||
|  | ||||
|                 LogUtils.d(TAG, "running..."); | ||||
|                 //LogUtils.d(TAG, "running..."); | ||||
|                 //ToastUtils.show("running..."); | ||||
|  | ||||
|             } else { | ||||
|                 LogUtils.d(TAG, "_mIsServiceAlive is " + Boolean.toString(_mIsServiceAlive)); | ||||
| @@ -94,6 +106,7 @@ public class MainService extends Service { | ||||
|         } | ||||
|         _mIsServiceAlive = false; | ||||
|         LogUtils.d(TAG, "onDestroy()"); | ||||
|         mContext = null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
| @@ -101,7 +114,7 @@ public class MainService extends Service { | ||||
|         LogUtils.d(TAG, "onStartCommand"); | ||||
|  | ||||
|         run(); | ||||
|         AppConfigs appConfigs = AppConfigs.loadAppConfigs(MainService.this); | ||||
|         AppConfigs appConfigs = AppConfigs.getInstance(MainService.this).loadAppConfigs(MainService.this); | ||||
|  | ||||
|         return appConfigs.isEnableService() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
| @@ -118,7 +131,7 @@ public class MainService extends Service { | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             //LogUtils.d(TAG, "call onServiceConnected(...)"); | ||||
|             AppConfigs appConfigs = AppConfigs.loadAppConfigs(MainService.this); | ||||
|             AppConfigs appConfigs = AppConfigs.getInstance(MainService.this).loadAppConfigs(MainService.this); | ||||
|             if (appConfigs.isEnableService()) { | ||||
|                 // 唤醒守护进程 | ||||
|                 wakeupAndBindAssistant(); | ||||
| @@ -160,7 +173,7 @@ public class MainService extends Service { | ||||
|  | ||||
|                     }); | ||||
|                 mFileListener.startWatching(); | ||||
|                 ToastUtils.show("Start watching."); | ||||
|                 //ToastUtils.show("Start watching."); | ||||
|             } else { | ||||
|                 // 父级文件夹不存在,就提示用户 | ||||
|                 Toast.makeText(getApplication(), fParentDir.toString() + " no exist.", Toast.LENGTH_SHORT).show(); | ||||
| @@ -176,6 +189,9 @@ public class MainService extends Service { | ||||
|     // 调用[应用信息查看器]打开应用包 | ||||
|     // | ||||
|     private void installAPK(String szAPKFilePath) { | ||||
|         String szAPKPackageName = PackageUtil.getPackageNameFromApk(this, szAPKFilePath); | ||||
|         saveAPKInfo(szAPKPackageName); | ||||
|  | ||||
|         long nTimeNow = System.currentTimeMillis(); | ||||
|         /*SimpleDateFormat dateFormat = new SimpleDateFormat( | ||||
|          "yyyy-MM-dd HH:mm:ss", Locale.getDefault()); | ||||
| @@ -210,15 +226,24 @@ public class MainService extends Service { | ||||
|     // | ||||
|     void installAPK2(String szAPKFilePath) { | ||||
|         LogUtils.d(TAG, "installAPK2()"); | ||||
|         String szAPKPackageName = PackageUtil.getPackageNameFromApk(this, szAPKFilePath); | ||||
|         saveAPKInfo(szAPKPackageName); | ||||
|  | ||||
|         Intent intent = new Intent(this, MainActivity.class); | ||||
|         intent.setAction(MainActivity.ACTION_NEW_INSTALLTASK); | ||||
|         intent.putExtra(MainActivity.EXTRA_INSTALLED_PACKAGENAME, PackageUtil.getPackageNameFromApk(this, szAPKFilePath)); | ||||
|         intent.putExtra(MainActivity.EXTRA_INSTALLED_PACKAGENAME, szAPKPackageName); | ||||
|         intent.putExtra(MainActivity.EXTRA_INSTALLED_APKFILEPATH, szAPKFilePath); | ||||
|         // Intent.ACTION_VIEW); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|         this.startActivity(intent); | ||||
|     } | ||||
|  | ||||
|     void saveAPKInfo(String szApkPackageName) { | ||||
|         APKModel.loadBeanList(this, _APKModelList, APKModel.class); | ||||
|         _APKModelList.add(new APKModel(szApkPackageName)); | ||||
|         APKModel.saveBeanList(this, _APKModelList, APKModel.class); | ||||
|     } | ||||
|  | ||||
|     //  | ||||
|     // | ||||
|     static class MyHandler extends Handler { | ||||
| @@ -231,7 +256,7 @@ public class MainService extends Service { | ||||
|             switch (message.what) { | ||||
|                 case MSG_INSTALL_APK: | ||||
|                     { | ||||
|                         AppConfigs appConfigs = AppConfigs.loadAppConfigs(theActivity); | ||||
|                         AppConfigs appConfigs = AppConfigs.getInstance(theActivity).loadAppConfigs(theActivity); | ||||
|                         if (appConfigs.getSetupMode() == AppConfigs.SetupMode.WATCHOUTPUTINSTALLER) { | ||||
|                             theActivity.installAPK2((String)message.obj); | ||||
|                         } else if (appConfigs.getSetupMode() == AppConfigs.SetupMode.NEWAPKINFONEWAPKINFO) { | ||||
| @@ -245,4 +270,21 @@ public class MainService extends Service { | ||||
|             super.handleMessage(message); | ||||
|         } | ||||
| 	} | ||||
|  | ||||
|     static class MainTileService extends TileService { | ||||
|         Context mContext; | ||||
|         MainTileService(Context context) { | ||||
|             mContext = context; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onStartListening() { | ||||
|             super.onStartListening(); | ||||
|             Tile tile = getQsTile(); | ||||
|             tile.setIcon(android.graphics.drawable.Icon.createWithResource(this, R.drawable.ic_android)); | ||||
|             // 更新磁贴状态 | ||||
|             tile.setState((mContext == null || mContext.getApplicationContext() == null )?Tile.STATE_INACTIVE: Tile.STATE_ACTIVE); | ||||
|             tile.updateTile(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| package cc.winboll.studio.autoinstaller.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/05/27 17:56:31 | ||||
|  * @Describe 文件管理类 | ||||
|  */ | ||||
|   | ||||
| @@ -55,8 +55,9 @@ public class NotificationUtil { | ||||
|  | ||||
|         Notification mForegroundNotification = new Notification.Builder(service, szServiceChannelID) | ||||
|             .setAutoCancel(true) | ||||
|             .setContentTitle(service.getString(R.string.app_name)) | ||||
|             .setContentText(service.TAG + " is started.") | ||||
|             //.setContentTitle(service.getString(R.string.app_name)) | ||||
|             .setContentTitle(service.TAG + " is started.") | ||||
|             //.setContentText(service.TAG + " is started.") | ||||
|             .setWhen(System.currentTimeMillis()) | ||||
|             .setSmallIcon(R.drawable.ic_launcher) | ||||
|             //设置红色 | ||||
|   | ||||
| @@ -1,14 +1,16 @@ | ||||
| package cc.winboll.studio.autoinstaller.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/12/11 06:28:50 | ||||
|  * @Describe 一个获取安卓APK安装文件的应用包名的函数 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.PackageInfo; | ||||
| import android.content.pm.PackageManager; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import android.content.pm.ResolveInfo; | ||||
| import cc.winboll.studio.libappbase.LogUtils; | ||||
|  | ||||
| public class PackageUtil { | ||||
|  | ||||
| @@ -27,4 +29,20 @@ public class PackageUtil { | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     public static void openAPP(Context context, String packageName) { | ||||
|         // 这里假设要打开微信,微信的包名是com.tencent.mm | ||||
|         //String packageName = "com.tencent.mm";  | ||||
|         LogUtils.d(TAG, "packageName : " + packageName); | ||||
|         PackageManager packageManager = context.getPackageManager(); | ||||
|         Intent intent = packageManager.getLaunchIntentForPackage(packageName); | ||||
|         if (intent != null) { | ||||
|             ResolveInfo resolveInfo = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); | ||||
|             if (resolveInfo != null) { | ||||
|                 LogUtils.d(TAG, "startActivity..."); | ||||
|                 context.startActivity(intent); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| package cc.winboll.studio.autoinstaller.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/05/27 20:20:03 | ||||
|  * @Describe 服务类工具 | ||||
|  */ | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#FF808080" | ||||
|         android:fillColor="#FF000000" | ||||
|         android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/> | ||||
| 
 | ||||
| </vector> | ||||
| @@ -8,4 +8,4 @@ | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M6.5,20Q4.22,20 2.61,18.43 1,16.85 1,14.58 1,12.63 2.17,11.1 3.35,9.57 5.25,9.15 5.88,6.85 7.75,5.43 9.63,4 12,4 14.93,4 16.96,6.04 19,8.07 19,11 20.73,11.2 21.86,12.5 23,13.78 23,15.5 23,17.38 21.69,18.69 20.38,20 18.5,20Z"/> | ||||
| 
 | ||||
| </vector> | ||||
| </vector> | ||||
| @@ -8,4 +8,4 @@ | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M6.5,20Q4.22,20 2.61,18.43 1,16.85 1,14.58 1,12.63 2.17,11.1 3.35,9.57 5.25,9.15 5.88,6.85 7.75,5.43 9.63,4 12,4 14.93,4 16.96,6.04 19,8.07 19,11 20.73,11.2 21.86,12.5 23,13.78 23,15.5 23,17.38 21.69,18.69 20.38,20 18.5,20M6.5,18H18.5Q19.55,18 20.27,17.27 21,16.55 21,15.5 21,14.45 20.27,13.73 19.55,13 18.5,13H17V11Q17,8.93 15.54,7.46 14.08,6 12,6 9.93,6 8.46,7.46 7,8.93 7,11H6.5Q5.05,11 4.03,12.03 3,13.05 3,14.5 3,15.95 4.03,17 5.05,18 6.5,18M12,12Z"/> | ||||
| 
 | ||||
| </vector> | ||||
| </vector> | ||||
| @@ -132,7 +132,7 @@ | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<cc.winboll.studio.shared.log.LogView | ||||
| 	<cc.winboll.studio.libappbase.LogView | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="200dp" | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| <resources> | ||||
|     <string name="app_name">AutoInstaller</string> | ||||
|     <string name="tileservice_name">AutoInstaller</string> | ||||
| </resources> | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|     <style name="MyAPPBaseTheme" parent="APPBaseTheme"> | ||||
| <resources xmlns:tools="http://schemas.android.com/tools"> | ||||
|     <style name="MyAppTheme" parent="APPBaseTheme"> | ||||
|         <item name="attrColorPrimary">@color/colorPrimary</item> | ||||
|         <item name="themeGlobalCrashActivity">@style/MyGlobalCrashActivityTheme</item> | ||||
|     </style> | ||||
| @@ -1,14 +0,0 @@ | ||||
| <resources xmlns:tools="http://schemas.android.com/tools"> | ||||
|     <!-- Base application theme. --> | ||||
|     <style name="Theme.Application" parent="android:Theme.Material.Light.DarkActionBar"> | ||||
|         <!-- Primary brand color. --> | ||||
|         <item name="android:colorPrimary">@color/purple_500</item> | ||||
|          | ||||
|         <!-- Secondary brand color. --> | ||||
|         <item name="android:colorSecondary">@color/teal_200</item> | ||||
|          | ||||
|         <!-- Status bar color. --> | ||||
|         <item name="android:statusBarColor" tools:targetApi="l">@color/purple_700</item> | ||||
|         <!-- Customize your theme here. --> | ||||
|     </style> | ||||
| </resources> | ||||
							
								
								
									
										30
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								build.gradle
									
									
									
									
									
								
							| @@ -1,11 +1,10 @@ | ||||
| // Top-level build file where you can add configuration options common to all sub-projects/modules. | ||||
| buildscript { | ||||
|     repositories { | ||||
|         // 本地 Maven 仓库(默认路径为 ~/.m2/repository) | ||||
|         mavenLocal() | ||||
|         // 或自定义本地仓库路径 | ||||
|         maven { url "file:///sdcard/.m2/repository" } | ||||
|          | ||||
|         mavenLocal { | ||||
|             // 设置本地Maven仓库路径 | ||||
|             url 'file:///sdcard/.m2/repository/' | ||||
|         } | ||||
|         // Nexus Maven 库地址 | ||||
|         // "WinBoLL Release" | ||||
|         maven { url "https://nexus.winboll.cc/repository/maven-public/" } | ||||
| @@ -20,7 +19,13 @@ buildscript { | ||||
|         maven { url "https://jitpack.io" } | ||||
|         mavenCentral() | ||||
|         google() | ||||
|         //println "mavenLocal : ===========" | ||||
|         //println mavenLocal().url | ||||
|         //println "mavenLocal : ===========" | ||||
|         //mavenLocal() | ||||
|          | ||||
|         // WinBoLL.CC 紧急备用 Maven 仓库 | ||||
|         maven { url 'https://spare-maven.winboll.cc/repository/' } | ||||
|     } | ||||
|     dependencies { | ||||
|         classpath 'com.android.tools.build:gradle:7.2.1' // 对应 compileSdkVersion 32 | ||||
| @@ -31,6 +36,11 @@ buildscript { | ||||
|  | ||||
| allprojects { | ||||
|     repositories { | ||||
|         mavenLocal { | ||||
|             // 设置本地Maven仓库路径 | ||||
|             url 'file:///sdcard/.m2/repository/' | ||||
|         } | ||||
|          | ||||
|         // Nexus Maven 库地址 | ||||
|         // "WinBoLL Release" | ||||
|         maven { url "https://nexus.winboll.cc/repository/maven-public/" } | ||||
| @@ -45,7 +55,13 @@ allprojects { | ||||
|         maven { url "https://jitpack.io" } | ||||
|         mavenCentral() | ||||
|         google() | ||||
|         mavenLocal() | ||||
|         //println "mavenLocal : ===========" | ||||
|         //println mavenLocal().url | ||||
|         //println "mavenLocal : ===========" | ||||
|         //mavenLocal() | ||||
|          | ||||
|         // WinBoLL.CC 紧急备用 Maven 仓库 | ||||
|         maven { url 'https://spare-maven.winboll.cc/repository/' } | ||||
|     } | ||||
|     ext { | ||||
|         // 定义全局变量,常用于版本管理 | ||||
| @@ -56,7 +72,7 @@ allprojects { | ||||
|         bashCommitAppPublishBuildFlagInfoFilePath = ".winboll/bashCommitAppPublishBuildFlagInfo.sh" | ||||
|          | ||||
|         winbollFilePath = "winboll.properties" | ||||
|         keyPropsFilePath = "current.keystore" | ||||
|         keyPropsFilePath = "appkey.keystore" | ||||
|         // 定义 lint 输出文件 | ||||
|         lintXmlReportFilePath = "build/reports/lint-results.xml" | ||||
|         lintHTMLReportFilePath = "build/reports/lint-results.html" | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| https://github.com/aJIEw/PhoneCallApp.git | ||||
|  | ||||
| #### 介绍 | ||||
| 通讯录与拨号 | ||||
| 这是可以根据正则表达式匹配拦截骚扰电话的手机拨号应用。 | ||||
|  | ||||
| #### 软件架构 | ||||
| 适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。 | ||||
| @@ -24,7 +24,7 @@ https://github.com/aJIEw/PhoneCallApp.git | ||||
|  | ||||
| 1.  Fork 本仓库 | ||||
| 2.  新建 Feat_xxx 分支 | ||||
| 3.  提交代码 : ZhanGSKen(ZhanGSKen@AliYun.Com) | ||||
| 3.  提交代码 : ZhanGSKen(ZhanGSKen<zhangsken@188.com>) | ||||
| 4.  新建 Pull Request | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -24,12 +24,12 @@ android { | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.contacts" | ||||
|         minSdkVersion 24 | ||||
|         targetSdkVersion 29 | ||||
|         targetSdkVersion 30 | ||||
|         versionCode 1 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // 项目模块目录的 build.gradle 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "15.2"  | ||||
|         versionName "15.3"  | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
| @@ -45,6 +45,9 @@ android { | ||||
|  | ||||
| dependencies { | ||||
|     api fileTree(dir: 'libs', include: ['*.jar']) | ||||
|     api 'cc.winboll.studio:libaes:15.9.3' | ||||
|     api 'cc.winboll.studio:libapputils:15.8.5' | ||||
|     api 'cc.winboll.studio:libappbase:15.9.5' | ||||
|      | ||||
|     // 权限请求框架:https://github.com/getActivity/XXPermissions | ||||
|     api 'com.github.getActivity:XXPermissions:18.63' | ||||
| @@ -81,8 +84,4 @@ dependencies { | ||||
|     //api 'androidx.vectordrawable:vectordrawable:1.1.0' | ||||
|     //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0' | ||||
|     //api 'androidx.fragment:fragment:1.1.0' | ||||
|      | ||||
|     api 'cc.winboll.studio:libaes:15.2.4' | ||||
|     api 'cc.winboll.studio:libapputils:15.2.1' | ||||
|     api 'cc.winboll.studio:libappbase:15.2.2' | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Sun Apr 13 02:46:09 HKT 2025 | ||||
| stageCount=8 | ||||
| #Sun Aug 31 06:05:42 CST 2025 | ||||
| stageCount=17 | ||||
| libraryProject= | ||||
| baseVersion=15.2 | ||||
| publishVersion=15.2.7 | ||||
| baseVersion=15.3 | ||||
| publishVersion=15.3.16 | ||||
| buildCount=0 | ||||
| baseBetaVersion=15.2.8 | ||||
| baseBetaVersion=15.3.17 | ||||
|   | ||||
| @@ -42,7 +42,8 @@ | ||||
|         android:icon="@drawable/ic_winboll" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/MyAppTheme" | ||||
|         android:supportsRtl="true"> | ||||
|         android:supportsRtl="true" | ||||
|         android:networkSecurityConfig="@xml/network_security_config"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".MainActivity" | ||||
| @@ -192,4 +193,4 @@ | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| </manifest> | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| package cc.winboll.studio.contacts; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Author ZhanGSKen<zhangsken@qq.com> | ||||
|  * @Date 2024/12/08 15:10:51 | ||||
|  * @Describe 全局应用类 | ||||
|  */ | ||||
| import android.view.Gravity; | ||||
| import cc.winboll.studio.libappbase.GlobalApplication; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBollActivityManager; | ||||
| import cc.winboll.studio.libappbase.winboll.WinBoLLActivityManager; | ||||
| import com.hjq.toast.ToastUtils; | ||||
|  | ||||
| public class App extends GlobalApplication { | ||||
| @@ -20,8 +20,8 @@ public class App extends GlobalApplication { | ||||
|         // 这样可以预先设置日志与数据的存储根目录。 | ||||
|         //setIsDebuging(BuildConfig.DEBUG); | ||||
|         super.onCreate(); | ||||
|         // 设置 WinBoll 应用 UI 类型 | ||||
|         WinBollActivityManager.getInstance(this).setWinBollUI_TYPE(WinBollActivityManager.WinBollUI_TYPE.Aplication); | ||||
|         // 设置 WinBoLL 应用 UI 类型 | ||||
|         getWinBoLLActivityManager().setWinBoLLUI_TYPE(WinBoLLActivityManager.WinBoLLUI_TYPE.Aplication); | ||||
|          | ||||
|         //LogUtils.d(TAG, "onCreate"); | ||||
|          | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user