Compare commits
	
		
			408 Commits
		
	
	
		
			aes-v15.8.
			...
			8014f4149c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					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 | ||
| 
						 | 
					053b45e87e | ||
| 
						 | 
					58e49ed371 | ||
| 
						 | 
					90a6eb266b | ||
| 
						 | 
					f0a564c9bb | ||
| 
						 | 
					46b21331af | ||
| 
						 | 
					6221cc30ac | ||
| 
						 | 
					8489ee6447 | ||
| 
						 | 
					9205af4aa9 | ||
| 
						 | 
					780e730a38 | ||
| 
						 | 
					429499885b | ||
| 
						 | 
					fcf4ad2fc0 | ||
| 
						 | 
					7635f6f084 | ||
| 
						 | 
					e49935f772 | ||
| 
						 | 
					381ddf9e40 | ||
| 
						 | 
					c687b5513d | ||
| 
						 | 
					7c7554133b | ||
| 
						 | 
					98f6d0019b | ||
| 
						 | 
					fc9c82921d | ||
| 
						 | 
					1ac0ad96e1 | ||
| 
						 | 
					9060cb51ff | ||
| 
						 | 
					7951d0a8d6 | ||
| 
						 | 
					ded775ae01 | ||
| 
						 | 
					82258f1763 | ||
| 
						 | 
					99bf53f27d | ||
| 
						 | 
					ddb6b53189 | ||
| 
						 | 
					ae8da772c0 | ||
| 
						 | 
					b2555ebfd3 | ||
| 
						 | 
					82d9aabf33 | ||
| 
						 | 
					e045bbb71c | ||
| 
						 | 
					d5782da040 | ||
| 
						 | 
					840da14438 | ||
| 
						 | 
					31595fe1ae | ||
| 
						 | 
					2c91d32e41 | ||
| 
						 | 
					58dabb7138 | ||
| 
						 | 
					3432575aa7 | ||
| 
						 | 
					fa43d43110 | ||
| 
						 | 
					8f8e7d98c7 | ||
| 
						 | 
					af39f98a51 | ||
| 
						 | 
					5a1d557683 | ||
| 
						 | 
					39116f0912 | ||
| 
						 | 
					a6b711b38b | ||
| 
						 | 
					d1703551f5 | ||
| 
						 | 
					d63f7d3d83 | ||
| 
						 | 
					06b399846d | ||
| 
						 | 
					e06efea08e | ||
| 
						 | 
					890ff6eda9 | ||
| 
						 | 
					e5a5eda9b6 | ||
| 
						 | 
					174a052088 | ||
| 
						 | 
					fbd8441264 | ||
| 
						 | 
					fb92e9f673 | ||
| 
						 | 
					d34d1e2796 | ||
| 
						 | 
					36fb8b41a4 | ||
| 
						 | 
					fe70a18547 | ||
| 
						 | 
					b61c63c426 | ||
| 
						 | 
					f02dc215ca | ||
| 
						 | 
					1c27d0ccdc | ||
| 
						 | 
					803745d12e | ||
| 
						 | 
					a66be9cd37 | ||
| 
						 | 
					46e4ee7fb7 | ||
| 
						 | 
					b2b959232c | ||
| 
						 | 
					b11f814c41 | ||
| 
						 | 
					1e991aed7e | ||
| 
						 | 
					f56125f82a | ||
| 
						 | 
					33b7b65239 | ||
| 
						 | 
					664d14ad84 | ||
| 
						 | 
					47cb393f76 | ||
| 
						 | 
					6495f1c66e | ||
| 
						 | 
					f0c52d1e02 | ||
| 
						 | 
					d948f31331 | ||
| 
						 | 
					e1b3087020 | ||
| 
						 | 
					03e21ab81c | ||
| 
						 | 
					ac72132969 | ||
| 
						 | 
					cedb5f521b | ||
| 
						 | 
					396df6713c | 
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,6 @@
 | 
				
			|||||||
[submodule "libjc/jcc/libs"]
 | 
					[submodule "libjc/jcc/libs"]
 | 
				
			||||||
	path = libjc/jcc/libs
 | 
						path = libjc/jcc/libs
 | 
				
			||||||
	url = https://gitea.winboll.cc/Studio/APP_libjc_jcc_libs.git
 | 
						url = https://gitea.winboll.cc/Studio/APP_libjc_jcc_libs.git
 | 
				
			||||||
 | 
					[submodule "keystore"]
 | 
				
			||||||
 | 
						path = keystore
 | 
				
			||||||
 | 
						url = https://gitea.winboll.cc/Studio/keystore.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已经提交了所有代码就执行标签和应用发布操作
 | 
					    # 如果Git已经提交了所有代码就执行标签和应用发布操作
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # 预先询问是否添加工作流标签
 | 
					    # 预先询问是否添加工作流标签
 | 
				
			||||||
    echo "Add Github Workflows Tag? (yes/No)"
 | 
					    #echo "Add Github Workflows Tag? (yes/No)"
 | 
				
			||||||
	result=$(askAddWorkflowsTag)
 | 
						#result=$(askAddWorkflowsTag)
 | 
				
			||||||
	nAskAddWorkflowsTag=$?
 | 
						#nAskAddWorkflowsTag=$?
 | 
				
			||||||
	echo $result
 | 
						#echo $result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # 发布应用
 | 
					    # 发布应用
 | 
				
			||||||
	echo "Publishing WinBoLL APK ..."
 | 
						echo "Publishing WinBoLL APK ..."
 | 
				
			||||||
@@ -138,17 +138,17 @@ if [[ $? -eq 0 ]]; then
 | 
				
			|||||||
	fi
 | 
						fi
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    # 添加 GitHub 工作流标签
 | 
					    # 添加 GitHub 工作流标签
 | 
				
			||||||
	if [[ $nAskAddWorkflowsTag -eq 1 ]]; then
 | 
						#if [[ $nAskAddWorkflowsTag -eq 1 ]]; then
 | 
				
			||||||
	    # 如果用户选择添加工作流标签
 | 
						    # 如果用户选择添加工作流标签
 | 
				
			||||||
    	result=$(addWorkflowsTag $1)
 | 
					    	#result=$(addWorkflowsTag $1)
 | 
				
			||||||
		if [[ $? -eq 0 ]]; then
 | 
							#if [[ $? -eq 0 ]]; then
 | 
				
			||||||
		    echo $result
 | 
							#    echo $result
 | 
				
			||||||
		    # 工作流标签添加成功
 | 
							    # 工作流标签添加成功
 | 
				
			||||||
		else
 | 
							#else
 | 
				
			||||||
			echo -e "${0}: addWorkflowsTag $1\n${result}\nAdd workflows tag cancel."
 | 
								#echo -e "${0}: addWorkflowsTag $1\n${result}\nAdd workflows tag cancel."
 | 
				
			||||||
			exit 1 # addWorkflowsTag 异常
 | 
								#exit 1 # addWorkflowsTag 异常
 | 
				
			||||||
		fi
 | 
							#fi
 | 
				
			||||||
	fi
 | 
						#fi
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	## 清理更新描述文件内容
 | 
						## 清理更新描述文件内容
 | 
				
			||||||
	echo "" > $1/app_update_description.txt
 | 
						echo "" > $1/app_update_description.txt
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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
 | 
				
			||||||
@@ -114,9 +114,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# 本项目要实际运用需要注意以下几个步骤:
 | 
					# 本项目要实际运用需要注意以下几个步骤:
 | 
				
			||||||
# 在项目根目录下:
 | 
					# 在项目根目录下:
 | 
				
			||||||
## 1. 项目模块编译环境设置(必须),settings.gradle-demo 要复制为 settings.gradle,并取消相应项目模块的注释。
 | 
					## ★. 项目模块编译环境设置(必须),settings.gradle-demo 要复制为 settings.gradle,并取消相应项目模块的注释。
 | 
				
			||||||
## 2. 项目 Android SDK 编译环境设置(可选),local.properties-demo 要复制为 local.properties,并按需要设置 Android SDK 目录。
 | 
					## ★. 项目模块编译环境设置(必须) 在根目录拷贝 gradle.properties-androidx-demo 或者 gradle.properties-android-demo 文件为 gradle.properties。
 | 
				
			||||||
## 3. 类库型模块编译环境设置(可选),winboll.properties-demo 要复制为 winboll.properties,并按需要设置 WinBoLL Maven 库登录用户信息。
 | 
					## ★. 项目 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 库登录用户信息。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ☆类库型项目编译方法
 | 
					# ☆类库型项目编译方法
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										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/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 参考文档
 | 
				
			||||||
@@ -29,7 +29,7 @@ android {
 | 
				
			|||||||
        // versionName 更新后需要手动设置 
 | 
					        // versionName 更新后需要手动设置 
 | 
				
			||||||
        // 项目模块目录的 build.gradle 文件的 stageCount=0
 | 
					        // 项目模块目录的 build.gradle 文件的 stageCount=0
 | 
				
			||||||
        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
					        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
				
			||||||
        versionName "15.8" 
 | 
					        versionName "15.9" 
 | 
				
			||||||
        if(true) {
 | 
					        if(true) {
 | 
				
			||||||
            versionName = genVersionName("${versionName}")
 | 
					            versionName = genVersionName("${versionName}")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#Created by .winboll/winboll_app_build.gradle
 | 
					#Created by .winboll/winboll_app_build.gradle
 | 
				
			||||||
#Tue May 13 11:22:23 HKT 2025
 | 
					#Sun Aug 31 23:40:17 HKT 2025
 | 
				
			||||||
stageCount=1
 | 
					stageCount=4
 | 
				
			||||||
libraryProject=libaes
 | 
					libraryProject=libaes
 | 
				
			||||||
baseVersion=15.8
 | 
					baseVersion=15.9
 | 
				
			||||||
publishVersion=15.8.0
 | 
					publishVersion=15.9.3
 | 
				
			||||||
buildCount=0
 | 
					buildCount=0
 | 
				
			||||||
baseBetaVersion=15.8.1
 | 
					baseBetaVersion=15.9.4
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.aes;
 | 
					package cc.winboll.studio.aes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/24 23:52:29
 | 
					 * @Date 2025/03/24 23:52:29
 | 
				
			||||||
 * @Describe AES应用介绍窗口
 | 
					 * @Describe AES应用介绍窗口
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -79,11 +79,11 @@ public class AboutActivity extends AppCompatActivity implements IWinBoLLActivity
 | 
				
			|||||||
        appInfo.setAppName("AES");
 | 
					        appInfo.setAppName("AES");
 | 
				
			||||||
        appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll);
 | 
					        appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll);
 | 
				
			||||||
        appInfo.setAppDescription("AES Description");
 | 
					        appInfo.setAppDescription("AES Description");
 | 
				
			||||||
        appInfo.setAppGitName("APP");
 | 
					        appInfo.setAppGitName("APPBase");
 | 
				
			||||||
        appInfo.setAppGitOwner("Studio");
 | 
					        appInfo.setAppGitOwner("Studio");
 | 
				
			||||||
        appInfo.setAppGitAPPBranch(szBranchName);
 | 
					        appInfo.setAppGitAPPBranch(szBranchName);
 | 
				
			||||||
        appInfo.setAppGitAPPSubProjectFolder(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.setAppAPKName("AES");
 | 
				
			||||||
        appInfo.setAppAPKFolderName("AES");
 | 
					        appInfo.setAppAPKFolderName("AES");
 | 
				
			||||||
        //appInfo.setIsAddDebugTools(false);
 | 
					        //appInfo.setIsAddDebugTools(false);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.aes;
 | 
					package cc.winboll.studio.aes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/06/13 19:03:58
 | 
					 * @Date 2024/06/13 19:03:58
 | 
				
			||||||
 * @Describe AES应用类
 | 
					 * @Describe AES应用类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.aes;
 | 
					package cc.winboll.studio.aes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/06/13 19:05:52
 | 
					 * @Date 2024/06/13 19:05:52
 | 
				
			||||||
 * @Describe 应用主窗口
 | 
					 * @Describe 应用主窗口
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ android {
 | 
				
			|||||||
    defaultConfig {
 | 
					    defaultConfig {
 | 
				
			||||||
        applicationId "cc.winboll.studio.androiddemo"
 | 
					        applicationId "cc.winboll.studio.androiddemo"
 | 
				
			||||||
        minSdkVersion 24
 | 
					        minSdkVersion 24
 | 
				
			||||||
        targetSdkVersion 29
 | 
					        targetSdkVersion 30
 | 
				
			||||||
        versionCode 1
 | 
					        versionCode 1
 | 
				
			||||||
        // versionName 更新后需要手动设置 
 | 
					        // versionName 更新后需要手动设置 
 | 
				
			||||||
        // .winboll/winbollBuildProps.properties 文件的 stageCount=0
 | 
					        // .winboll/winbollBuildProps.properties 文件的 stageCount=0
 | 
				
			||||||
@@ -67,6 +67,6 @@ dependencies {
 | 
				
			|||||||
    // https://mvnrepository.com/artifact/com.android.support/recyclerview-v7
 | 
					    // https://mvnrepository.com/artifact/com.android.support/recyclerview-v7
 | 
				
			||||||
    api 'com.android.support:recyclerview-v7:28.0.0'
 | 
					    api 'com.android.support:recyclerview-v7:28.0.0'
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    api 'cc.winboll.studio:libapputils:15.2.2'
 | 
					    api 'cc.winboll.studio:libapputils:15.8.5'
 | 
				
			||||||
    api 'cc.winboll.studio:libappbase:15.2.2'
 | 
					    api 'cc.winboll.studio:libappbase:15.9.5'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#Created by .winboll/winboll_app_build.gradle
 | 
					#Created by .winboll/winboll_app_build.gradle
 | 
				
			||||||
#Thu Apr 03 03:17:18 GMT 2025
 | 
					#Sun Aug 31 05:11:26 CST 2025
 | 
				
			||||||
stageCount=0
 | 
					stageCount=1
 | 
				
			||||||
libraryProject=
 | 
					libraryProject=
 | 
				
			||||||
baseVersion=15.0
 | 
					baseVersion=15.0
 | 
				
			||||||
publishVersion=15.0.0
 | 
					publishVersion=15.0.0
 | 
				
			||||||
buildCount=21
 | 
					buildCount=0
 | 
				
			||||||
baseBetaVersion=15.0.1
 | 
					baseBetaVersion=15.0.1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,12 +24,12 @@ android {
 | 
				
			|||||||
    defaultConfig {
 | 
					    defaultConfig {
 | 
				
			||||||
        applicationId "cc.winboll.studio.androidxdemo"
 | 
					        applicationId "cc.winboll.studio.androidxdemo"
 | 
				
			||||||
        minSdkVersion 24
 | 
					        minSdkVersion 24
 | 
				
			||||||
        targetSdkVersion 29
 | 
					        targetSdkVersion 30
 | 
				
			||||||
        versionCode 1
 | 
					        versionCode 1
 | 
				
			||||||
        // versionName 更新后需要手动设置 
 | 
					        // versionName 更新后需要手动设置 
 | 
				
			||||||
        // .winboll/winbollBuildProps.properties 文件的 stageCount=0
 | 
					        // .winboll/winbollBuildProps.properties 文件的 stageCount=0
 | 
				
			||||||
        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
					        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
				
			||||||
        versionName "15.0"
 | 
					        versionName "15.1"
 | 
				
			||||||
        if(true) {
 | 
					        if(true) {
 | 
				
			||||||
            versionName = genVersionName("${versionName}")
 | 
					            versionName = genVersionName("${versionName}")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -67,7 +67,7 @@ dependencies {
 | 
				
			|||||||
    //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
 | 
					    //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
 | 
				
			||||||
    //api 'androidx.fragment:fragment:1.1.0'
 | 
					    //api 'androidx.fragment:fragment:1.1.0'
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    api 'cc.winboll.studio:libaes:15.2.6'
 | 
					    api 'cc.winboll.studio:libaes:15.9.3'
 | 
				
			||||||
    api 'cc.winboll.studio:libapputils:15.2.2'
 | 
					    api 'cc.winboll.studio:libapputils:15.8.5'
 | 
				
			||||||
    api 'cc.winboll.studio:libappbase:15.2.2'
 | 
					    api 'cc.winboll.studio:libappbase:15.9.5'
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#Created by .winboll/winboll_app_build.gradle
 | 
					#Created by .winboll/winboll_app_build.gradle
 | 
				
			||||||
#Thu Apr 03 03:15:55 GMT 2025
 | 
					#Sun Aug 31 05:42:50 CST 2025
 | 
				
			||||||
stageCount=0
 | 
					stageCount=2
 | 
				
			||||||
libraryProject=
 | 
					libraryProject=
 | 
				
			||||||
baseVersion=15.0
 | 
					baseVersion=15.1
 | 
				
			||||||
publishVersion=15.0.0
 | 
					publishVersion=15.1.1
 | 
				
			||||||
buildCount=18
 | 
					buildCount=0
 | 
				
			||||||
baseBetaVersion=15.0.1
 | 
					baseBetaVersion=15.1.2
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,9 +22,9 @@ import android.widget.HorizontalScrollView;
 | 
				
			|||||||
import android.widget.ScrollView;
 | 
					import android.widget.ScrollView;
 | 
				
			||||||
import android.widget.TextView;
 | 
					import android.widget.TextView;
 | 
				
			||||||
import android.widget.Toast;
 | 
					import android.widget.Toast;
 | 
				
			||||||
import cc.winboll.studio.androidxdemo.R;
 | 
					 | 
				
			||||||
import cc.winboll.studio.libappbase.GlobalApplication;
 | 
					import cc.winboll.studio.libappbase.GlobalApplication;
 | 
				
			||||||
import com.hjq.toast.ToastUtils;
 | 
					import com.hjq.toast.ToastUtils;
 | 
				
			||||||
 | 
					import com.hjq.toast.style.WhiteToastStyle;
 | 
				
			||||||
import java.io.ByteArrayInputStream;
 | 
					import java.io.ByteArrayInputStream;
 | 
				
			||||||
import java.io.ByteArrayOutputStream;
 | 
					import java.io.ByteArrayOutputStream;
 | 
				
			||||||
import java.io.Closeable;
 | 
					import java.io.Closeable;
 | 
				
			||||||
@@ -53,8 +53,8 @@ public class App extends GlobalApplication {
 | 
				
			|||||||
        // 初始化 Toast 框架
 | 
					        // 初始化 Toast 框架
 | 
				
			||||||
        ToastUtils.init(this);
 | 
					        ToastUtils.init(this);
 | 
				
			||||||
        // 设置 Toast 布局样式
 | 
					        // 设置 Toast 布局样式
 | 
				
			||||||
        ToastUtils.setView(R.layout.view_toast);
 | 
					        //ToastUtils.setView(R.layout.view_toast);
 | 
				
			||||||
        //ToastUtils.setStyle(new WhiteToastStyle());
 | 
					        ToastUtils.setStyle(new WhiteToastStyle());
 | 
				
			||||||
        ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
 | 
					        ToastUtils.setGravity(Gravity.BOTTOM, 0, 200);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        //CrashHandler.getInstance().registerGlobal(this);
 | 
					        //CrashHandler.getInstance().registerGlobal(this);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ android {
 | 
				
			|||||||
        // versionName 更新后需要手动设置 
 | 
					        // versionName 更新后需要手动设置 
 | 
				
			||||||
        // .winboll/winbollBuildProps.properties 文件的 stageCount=0
 | 
					        // .winboll/winbollBuildProps.properties 文件的 stageCount=0
 | 
				
			||||||
        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
					        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
				
			||||||
        versionName "15.7"
 | 
					        versionName "15.9"
 | 
				
			||||||
        if(true) {
 | 
					        if(true) {
 | 
				
			||||||
            versionName = genVersionName("${versionName}")
 | 
					            versionName = genVersionName("${versionName}")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#Created by .winboll/winboll_app_build.gradle
 | 
					#Created by .winboll/winboll_app_build.gradle
 | 
				
			||||||
#Sun May 11 19:36:35 GMT 2025
 | 
					#Fri Sep 12 02:40:06 GMT 2025
 | 
				
			||||||
stageCount=7
 | 
					stageCount=6
 | 
				
			||||||
libraryProject=libappbase
 | 
					libraryProject=libappbase
 | 
				
			||||||
baseVersion=15.7
 | 
					baseVersion=15.9
 | 
				
			||||||
publishVersion=15.7.6
 | 
					publishVersion=15.9.5
 | 
				
			||||||
buildCount=15
 | 
					buildCount=4
 | 
				
			||||||
baseBetaVersion=15.7.7
 | 
					baseBetaVersion=15.9.6
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,8 @@
 | 
				
			|||||||
        android:label="@string/app_name"
 | 
					        android:label="@string/app_name"
 | 
				
			||||||
        android:theme="@style/MyAPPBaseTheme"
 | 
					        android:theme="@style/MyAPPBaseTheme"
 | 
				
			||||||
        android:resizeableActivity="true"
 | 
					        android:resizeableActivity="true"
 | 
				
			||||||
        android:process=":App">
 | 
					        android:process=":App"
 | 
				
			||||||
 | 
					        android:networkSecurityConfig="@xml/network_security_config">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <activity
 | 
					        <activity
 | 
				
			||||||
            android:name=".MainActivity"
 | 
					            android:name=".MainActivity"
 | 
				
			||||||
@@ -39,7 +40,8 @@
 | 
				
			|||||||
            android:resizeableActivity="true"
 | 
					            android:resizeableActivity="true"
 | 
				
			||||||
            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/>
 | 
					            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <activity android:name=".activities.New2Activity"
 | 
					        <activity
 | 
				
			||||||
 | 
					            android:name=".activities.New2Activity"
 | 
				
			||||||
            android:label="New2Activity"
 | 
					            android:label="New2Activity"
 | 
				
			||||||
            android:exported="true"
 | 
					            android:exported="true"
 | 
				
			||||||
            android:resizeableActivity="true"
 | 
					            android:resizeableActivity="true"
 | 
				
			||||||
@@ -74,7 +76,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        <service android:name=".services.AssistantService"/>
 | 
					        <service android:name=".services.AssistantService"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <receiver android:name="cc.winboll.studio.appbase.receivers.MainReceiver"
 | 
					        <receiver
 | 
				
			||||||
 | 
					            android:name="cc.winboll.studio.appbase.receivers.MainReceiver"
 | 
				
			||||||
            android:exported="true">
 | 
					            android:exported="true">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <intent-filter>
 | 
					            <intent-filter>
 | 
				
			||||||
@@ -105,7 +108,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        </receiver>
 | 
					        </receiver>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <receiver android:name=".receivers.APPNewsWidgetClickListener"
 | 
					        <receiver
 | 
				
			||||||
 | 
					            android:name=".receivers.APPNewsWidgetClickListener"
 | 
				
			||||||
            android:exported="true">
 | 
					            android:exported="true">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <intent-filter>
 | 
					            <intent-filter>
 | 
				
			||||||
@@ -122,7 +126,6 @@
 | 
				
			|||||||
            android:name="android.max_aspect"
 | 
					            android:name="android.max_aspect"
 | 
				
			||||||
            android:value="4.0"/>
 | 
					            android:value="4.0"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    </application>
 | 
					    </application>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</manifest>
 | 
					</manifest>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase;
 | 
					package cc.winboll.studio.appbase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/01/05 09:54:42
 | 
					 * @Date 2025/01/05 09:54:42
 | 
				
			||||||
 * @Describe APPbase 应用类
 | 
					 * @Describe APPbase 应用类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,7 +40,6 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Toolbar mToolbar;
 | 
					    Toolbar mToolbar;
 | 
				
			||||||
    LogView mLogView;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
					    protected void onCreate(Bundle savedInstanceState) {
 | 
				
			||||||
@@ -53,19 +52,21 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1);
 | 
					        CheckBox cbIsDebugMode = findViewById(R.id.activitymainCheckBox1);
 | 
				
			||||||
        cbIsDebugMode.setChecked(GlobalApplication.isDebuging());
 | 
					        cbIsDebugMode.setChecked(GlobalApplication.isDebuging());
 | 
				
			||||||
        mLogView = findViewById(R.id.logview);
 | 
					 | 
				
			||||||
        mLogView.start(); 
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onCreateOptionsMenu(Menu menu) {
 | 
					    public boolean onCreateOptionsMenu(Menu menu) {
 | 
				
			||||||
        getMenuInflater().inflate(R.menu.toolbar_main, menu);
 | 
					        getMenuInflater().inflate(R.menu.toolbar_main, menu);
 | 
				
			||||||
        getMenuInflater().inflate(R.menu.toolbar_appbase, menu);
 | 
					 | 
				
			||||||
        return super.onCreateOptionsMenu(menu);
 | 
					        return super.onCreateOptionsMenu(menu);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onOptionsItemSelected(MenuItem item) {
 | 
					    public boolean onOptionsItemSelected(MenuItem item) {
 | 
				
			||||||
 | 
					        if(item.getItemId() == R.id.item_yun) {
 | 
				
			||||||
 | 
					            GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, cc.winboll.studio.libappbase.activities.YunActivity.class);
 | 
				
			||||||
 | 
					        } else if(item.getItemId() == R.id.item_logon) {
 | 
				
			||||||
 | 
					            GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(this, cc.winboll.studio.libappbase.activities.LogonActivity.class);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。
 | 
					        // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。
 | 
				
			||||||
        return super.onOptionsItemSelected(item);
 | 
					        return super.onOptionsItemSelected(item);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -176,8 +177,7 @@ public class MainActivity extends WinBoLLActivity implements IWinBoLLActivity {
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected void onResume() {
 | 
					    protected void onResume() {
 | 
				
			||||||
        super.onResume();
 | 
					        super.onResume();
 | 
				
			||||||
        mLogView.start();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase;
 | 
					package cc.winboll.studio.appbase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/13 19:30:10
 | 
					 * @Date 2025/02/13 19:30:10
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.content.Context;
 | 
					import android.content.Context;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.activities;
 | 
					package cc.winboll.studio.appbase.activities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/25 11:46:40
 | 
					 * @Date 2025/03/25 11:46:40
 | 
				
			||||||
 * @Describe 测试窗口2
 | 
					 * @Describe 测试窗口2
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -66,16 +66,11 @@ public class New2Activity extends WinBoLLActivity implements IWinBoLLActivity {
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onCreateOptionsMenu(Menu menu) {
 | 
					    public boolean onCreateOptionsMenu(Menu menu) {
 | 
				
			||||||
        getMenuInflater().inflate(R.menu.toolbar_main, menu);
 | 
					        getMenuInflater().inflate(R.menu.toolbar_main, menu);
 | 
				
			||||||
        getMenuInflater().inflate(R.menu.toolbar_appbase, menu);
 | 
					 | 
				
			||||||
        return super.onCreateOptionsMenu(menu);
 | 
					        return super.onCreateOptionsMenu(menu);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onOptionsItemSelected(MenuItem item) {
 | 
					    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。
 | 
					        // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。
 | 
				
			||||||
        return super.onOptionsItemSelected(item);
 | 
					        return super.onOptionsItemSelected(item);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.activities;
 | 
					package cc.winboll.studio.appbase.activities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/25 05:04:22
 | 
					 * @Date 2025/03/25 05:04:22
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.app.Activity;
 | 
					import android.app.Activity;
 | 
				
			||||||
@@ -64,16 +64,11 @@ public class NewActivity extends WinBoLLActivity implements IWinBoLLActivity {
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onCreateOptionsMenu(Menu menu) {
 | 
					    public boolean onCreateOptionsMenu(Menu menu) {
 | 
				
			||||||
        getMenuInflater().inflate(R.menu.toolbar_main, menu);
 | 
					        getMenuInflater().inflate(R.menu.toolbar_main, menu);
 | 
				
			||||||
        getMenuInflater().inflate(R.menu.toolbar_appbase, menu);
 | 
					 | 
				
			||||||
        return super.onCreateOptionsMenu(menu);
 | 
					        return super.onCreateOptionsMenu(menu);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onOptionsItemSelected(MenuItem item) {
 | 
					    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。
 | 
					        // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。
 | 
				
			||||||
        return super.onOptionsItemSelected(item);
 | 
					        return super.onOptionsItemSelected(item);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,17 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.activities;
 | 
					package cc.winboll.studio.appbase.activities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/05/10 09:48
 | 
					 * @Date 2025/05/10 09:48
 | 
				
			||||||
 * @Describe WinBoLL 窗口基础类
 | 
					 * @Describe WinBoLL 窗口基础类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.app.Activity;
 | 
					import android.app.Activity;
 | 
				
			||||||
 | 
					import android.os.Bundle;
 | 
				
			||||||
 | 
					import android.view.MenuItem;
 | 
				
			||||||
 | 
					import cc.winboll.studio.appbase.MainActivity;
 | 
				
			||||||
 | 
					import cc.winboll.studio.appbase.R;
 | 
				
			||||||
 | 
					import cc.winboll.studio.libappbase.GlobalApplication;
 | 
				
			||||||
 | 
					import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			||||||
import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
 | 
					import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class WinBoLLActivity extends Activity implements IWinBoLLActivity {
 | 
					public class WinBoLLActivity extends Activity implements IWinBoLLActivity {
 | 
				
			||||||
@@ -21,4 +27,35 @@ public class WinBoLLActivity extends Activity implements IWinBoLLActivity {
 | 
				
			|||||||
    public String getTag() {
 | 
					    public String getTag() {
 | 
				
			||||||
        return TAG;
 | 
					        return TAG;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected void onResume() {
 | 
				
			||||||
 | 
					        super.onResume();
 | 
				
			||||||
 | 
					        LogUtils.d(TAG, String.format("onResume %s", getTag()));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean onOptionsItemSelected(MenuItem item) {
 | 
				
			||||||
 | 
					        if (item.getItemId() == R.id.item_log) {
 | 
				
			||||||
 | 
					            GlobalApplication.getWinBoLLActivityManager().startLogActivity(this);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } else if (item.getItemId() == R.id.item_home) {
 | 
				
			||||||
 | 
					            GlobalApplication.getWinBoLLActivityManager().startWinBoLLActivity(getApplicationContext(), MainActivity.class);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 在switch语句中处理每个ID,并在处理完后返回true,未处理的情况返回false。
 | 
				
			||||||
 | 
					        return super.onOptionsItemSelected(item);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected void onPostCreate(Bundle savedInstanceState) {
 | 
				
			||||||
 | 
					        super.onPostCreate(savedInstanceState);
 | 
				
			||||||
 | 
					        GlobalApplication.getWinBoLLActivityManager().add(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected void onDestroy() {
 | 
				
			||||||
 | 
					        super.onDestroy();
 | 
				
			||||||
 | 
					        GlobalApplication.getWinBoLLActivityManager().registeRemove(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.handlers;
 | 
					package cc.winboll.studio.appbase.handlers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/14 03:51:40
 | 
					 * @Date 2025/02/14 03:51:40
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.os.Handler;
 | 
					import android.os.Handler;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.models;
 | 
					package cc.winboll.studio.appbase.models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/13 07:06:13
 | 
					 * @Date 2025/02/13 07:06:13
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.util.JsonReader;
 | 
					import android.util.JsonReader;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.models;
 | 
					package cc.winboll.studio.appbase.models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/07 12:47:22
 | 
					 * @Date 2025/03/07 12:47:22
 | 
				
			||||||
 * @Describe TestServiceBean
 | 
					 * @Describe TestServiceBean
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.models;
 | 
					package cc.winboll.studio.appbase.models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/07 12:49:21
 | 
					 * @Date 2025/03/07 12:49:21
 | 
				
			||||||
 * @Describe TestDemoServiceBean
 | 
					 * @Describe TestDemoServiceBean
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.receivers;
 | 
					package cc.winboll.studio.appbase.receivers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/24 07:11:44
 | 
					 * @Date 2025/03/24 07:11:44
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.content.BroadcastReceiver;
 | 
					import android.content.BroadcastReceiver;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.receivers;
 | 
					package cc.winboll.studio.appbase.receivers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/13 06:58:04
 | 
					 * @Date 2025/02/13 06:58:04
 | 
				
			||||||
 * @Describe 主要广播接收器
 | 
					 * @Describe 主要广播接收器
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.services;
 | 
					package cc.winboll.studio.appbase.services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/14 03:38:31
 | 
					 * @Date 2025/02/14 03:38:31
 | 
				
			||||||
 * @Describe 守护进程服务
 | 
					 * @Describe 守护进程服务
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.services;
 | 
					package cc.winboll.studio.appbase.services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/13 06:56:41
 | 
					 * @Date 2025/02/13 06:56:41
 | 
				
			||||||
 * @Describe 拨号主服务
 | 
					 * @Describe 拨号主服务
 | 
				
			||||||
 * 参考:
 | 
					 * 参考:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.services;
 | 
					package cc.winboll.studio.appbase.services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/07 12:45:49
 | 
					 * @Date 2025/03/07 12:45:49
 | 
				
			||||||
 * @Describe 启动时申请绑定到APPBase主服务的服务示例
 | 
					 * @Describe 启动时申请绑定到APPBase主服务的服务示例
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.services;
 | 
					package cc.winboll.studio.appbase.services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/07 12:39:24
 | 
					 * @Date 2025/03/07 12:39:24
 | 
				
			||||||
 * @Describe 普通服务示例
 | 
					 * @Describe 普通服务示例
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.threads;
 | 
					package cc.winboll.studio.appbase.threads;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/14 03:46:44
 | 
					 * @Date 2025/02/14 03:46:44
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.content.Context;
 | 
					import android.content.Context;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package cc.winboll.studio.appbase.widgets;
 | 
					package cc.winboll.studio.appbase.widgets;
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/15 14:41:25
 | 
					 * @Date 2025/02/15 14:41:25
 | 
				
			||||||
 * @Describe TimeWidget
 | 
					 * @Describe TimeWidget
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,13 +32,19 @@
 | 
				
			|||||||
				<TextView
 | 
									<TextView
 | 
				
			||||||
					android:layout_width="wrap_content"
 | 
										android:layout_width="wrap_content"
 | 
				
			||||||
					android:layout_height="wrap_content"
 | 
										android:layout_height="wrap_content"
 | 
				
			||||||
					android:text="Hello, WinBoLL!"/>
 | 
										android:text="安卓R对应的是Android 11,其API级别是30。以下是Android 11中一些重要的API相关特性:
 | 
				
			||||||
 | 
					 | 
				
			||||||
				<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,但可能需要注意兼容性和配置问题。"/>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    \n- 隐私保护方面:引入单次授权,让用户可以选择授予应用对位置信息、麦克风和摄像头的临时访问权限。还增加了数据访问审核功能,能让开发者深入了解应用在何处访问私密数据。
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    \n- 系统功能方面:提供了ControlsProviderService API,用于向连接的外部设备提供控件,这些控件显示于Android电源菜单中的设备控件下。媒体控件也得到更新,显示于快捷设置旁,来自多个应用的会话排列在一个可滑动的轮播界面中。
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    \n- 硬件支持方面:提供了一些API以支持瀑布屏,通过将窗口布局属性  layoutInDisplayCutoutMode  设为  LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS ,可允许窗口延伸到屏幕各个边缘上的刘海和瀑布区域。对于合页式屏幕配置的设备,提供了具有  TYPE_HINGE_ANGLE  的新传感器以及新的  SensorEvent ,用于监控合页角度。
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    \n- 安全方面:对生物识别身份验证机制进行了更新,引入了  BiometricManager.Authenticators  接口,定义了  BIOMETRIC_STRONG 、 BIOMETRIC_WEAK 、 DEVICE_CREDENTIAL  等身份验证类型。还在  BiometricPrompt  类中提供了对“每次使用时进行身份验证”密钥的更多支持。
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    \n- 性能和质量方面:支持无线调试,通过Android调试桥(adb)从工作站以无线方式部署和调试应用,避免了常见的USB连接问题。"/>
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
				<HorizontalScrollView
 | 
									<HorizontalScrollView
 | 
				
			||||||
					android:layout_width="match_parent"
 | 
										android:layout_width="match_parent"
 | 
				
			||||||
					android:layout_height="wrap_content">
 | 
										android:layout_height="wrap_content">
 | 
				
			||||||
@@ -211,11 +217,5 @@
 | 
				
			|||||||
		</LinearLayout>
 | 
							</LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	</ScrollView>
 | 
						</ScrollView>
 | 
				
			||||||
 | 
					 | 
				
			||||||
	<cc.winboll.studio.libappbase.LogView
 | 
					 | 
				
			||||||
		android:layout_width="match_parent"
 | 
					 | 
				
			||||||
		android:layout_height="300dp"
 | 
					 | 
				
			||||||
		android:id="@+id/logview"/>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
</LinearLayout>
 | 
					</LinearLayout>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,20 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="utf-8"?>
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
 | 
					<menu xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
	xmlns:app="http://schemas.android.com/apk/res-auto">
 | 
						xmlns:app="http://schemas.android.com/apk/res-auto">
 | 
				
			||||||
    
 | 
					    <item
 | 
				
			||||||
    
 | 
					        android:id="@+id/item_home"
 | 
				
			||||||
 | 
					        android:title="HOME"
 | 
				
			||||||
 | 
					        android:icon="@drawable/ic_winboll"/>
 | 
				
			||||||
 | 
					    <item
 | 
				
			||||||
 | 
					        android:id="@+id/item_yun"
 | 
				
			||||||
 | 
					        android:title="YUN"
 | 
				
			||||||
 | 
					        android:icon="@drawable/ic_winboll"/>
 | 
				
			||||||
 | 
					    <item
 | 
				
			||||||
 | 
					        android:id="@+id/item_logon"
 | 
				
			||||||
 | 
					        android:title="Logon"
 | 
				
			||||||
 | 
					        android:icon="@drawable/ic_winboll"/>
 | 
				
			||||||
 | 
					    <item
 | 
				
			||||||
 | 
					        android:id="@+id/item_log"
 | 
				
			||||||
 | 
					        android:title="LOG"
 | 
				
			||||||
 | 
					        android:icon="@drawable/ic_winboll_log"/>
 | 
				
			||||||
</menu>
 | 
					</menu>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								appbase/src/main/res/xml/network_security_config.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								appbase/src/main/res/xml/network_security_config.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<network-security-config>
 | 
				
			||||||
 | 
					    <!-- 允许访问 winboll.cc 及其子域名(原配置) -->
 | 
				
			||||||
 | 
					    <domain-config cleartextTrafficPermitted="true">
 | 
				
			||||||
 | 
					        <domain includeSubdomains="true">winboll.cc</domain>
 | 
				
			||||||
 | 
					    </domain-config>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- **新增:允许访问 IP 地址 10.8.0.250** -->
 | 
				
			||||||
 | 
					    <domain-config cleartextTrafficPermitted="true">
 | 
				
			||||||
 | 
					        <domain includeSubdomains="false">10.8.0.250</domain> <!-- 不包含子域名 -->
 | 
				
			||||||
 | 
					    </domain-config>
 | 
				
			||||||
 | 
					</network-security-config>
 | 
				
			||||||
@@ -29,7 +29,7 @@ android {
 | 
				
			|||||||
        // versionName 更新后需要手动设置 
 | 
					        // versionName 更新后需要手动设置 
 | 
				
			||||||
        // 项目模块目录的 build.gradle 文件的 stageCount=0
 | 
					        // 项目模块目录的 build.gradle 文件的 stageCount=0
 | 
				
			||||||
        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
					        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
				
			||||||
        versionName "15.3" 
 | 
					        versionName "15.8" 
 | 
				
			||||||
        if(true) {
 | 
					        if(true) {
 | 
				
			||||||
            versionName = genVersionName("${versionName}")
 | 
					            versionName = genVersionName("${versionName}")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#Created by .winboll/winboll_app_build.gradle
 | 
					#Created by .winboll/winboll_app_build.gradle
 | 
				
			||||||
#Tue Apr 29 15:04:17 HKT 2025
 | 
					#Mon Sep 01 07:56:33 HKT 2025
 | 
				
			||||||
stageCount=5
 | 
					stageCount=7
 | 
				
			||||||
libraryProject=libapputils
 | 
					libraryProject=libapputils
 | 
				
			||||||
baseVersion=15.3
 | 
					baseVersion=15.8
 | 
				
			||||||
publishVersion=15.3.4
 | 
					publishVersion=15.8.6
 | 
				
			||||||
buildCount=0
 | 
					buildCount=0
 | 
				
			||||||
baseBetaVersion=15.3.5
 | 
					baseBetaVersion=15.8.7
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.apputils;
 | 
					package cc.winboll.studio.apputils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/12/08 15:10:51
 | 
					 * @Date 2024/12/08 15:10:51
 | 
				
			||||||
 * @Describe 全局应用类
 | 
					 * @Describe 全局应用类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.apputils;
 | 
					package cc.winboll.studio.apputils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/01/03 11:02:49
 | 
					 * @Date 2025/01/03 11:02:49
 | 
				
			||||||
 * @Describe 一个可以浏览随 APP 附带的 Html 文档的窗口
 | 
					 * @Describe 一个可以浏览随 APP 附带的 Html 文档的窗口
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -20,18 +20,7 @@ import cc.winboll.studio.libapputils.views.SimpleWebView;
 | 
				
			|||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.io.InputStream;
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class AssetsHtmlActivity extends WinBoLLActivityBase implements IWinBoLLActivity {
 | 
					public class AssetsHtmlActivity extends WinBoLLActivity implements IWinBoLLActivity {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public Activity getActivity() {
 | 
					 | 
				
			||||||
        return super.getActivity();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public String getTag() {
 | 
					 | 
				
			||||||
        return TAG;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static final String TAG = "AssetsHtmlActivity";
 | 
					    public static final String TAG = "AssetsHtmlActivity";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -43,12 +32,17 @@ public class AssetsHtmlActivity extends WinBoLLActivityBase implements IWinBoLLA
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Assets 文件夹里的 Html 文件的名称
 | 
					    // Assets 文件夹里的 Html 文件的名称
 | 
				
			||||||
    String mszHtmlFileName;
 | 
					    String mszHtmlFileName;
 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//    @Override
 | 
					 | 
				
			||||||
//    public Activity getActivity() {
 | 
					 | 
				
			||||||
//        return this;
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Activity getActivity() {
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String getTag() {
 | 
				
			||||||
 | 
					        return TAG;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onCreateOptionsMenu(Menu menu) {
 | 
					    public boolean onCreateOptionsMenu(Menu menu) {
 | 
				
			||||||
        return super.onCreateOptionsMenu(menu);
 | 
					        return super.onCreateOptionsMenu(menu);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -217,10 +217,10 @@ final public class MainActivity extends Activity {
 | 
				
			|||||||
        if (item.getItemId() == R.id.item_exit) {
 | 
					        if (item.getItemId() == R.id.item_exit) {
 | 
				
			||||||
            //exit();
 | 
					            //exit();
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        } else if (item.getItemId() == R.id.item_teststringtoqrcodeview) {
 | 
					//        } else if (item.getItemId() == R.id.item_teststringtoqrcodeview) {
 | 
				
			||||||
            Intent intent = new Intent(this, TestStringToQRCodeViewActivity.class);
 | 
					//            Intent intent = new Intent(this, TestStringToQRCodeViewActivity.class);
 | 
				
			||||||
            startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY);
 | 
					//            startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY);
 | 
				
			||||||
            //WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(this, TestStringToQrCodeViewActivity.class);
 | 
					//            //WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(this, TestStringToQrCodeViewActivity.class);
 | 
				
			||||||
        } else if (item.getItemId() == R.id.item_testqrcodedecodeactivity) {
 | 
					        } else if (item.getItemId() == R.id.item_testqrcodedecodeactivity) {
 | 
				
			||||||
            Intent intent = new Intent(this, QRCodeDecodeActivity.class);
 | 
					            Intent intent = new Intent(this, QRCodeDecodeActivity.class);
 | 
				
			||||||
            startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY);
 | 
					            startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.apputils;
 | 
					package cc.winboll.studio.apputils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/01/18 10:32:21
 | 
					 * @Date 2025/01/18 10:32:21
 | 
				
			||||||
 * @Describe 二维码扫码解码窗口
 | 
					 * @Describe 二维码扫码解码窗口
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.apputils;
 | 
					package cc.winboll.studio.apputils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/23 16:14:45
 | 
					 * @Date 2025/03/23 16:14:45
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.app.Activity;
 | 
					import android.app.Activity;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					package cc.winboll.studio.apputils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 | 
					 * @Date 2025/05/13 11:15
 | 
				
			||||||
 | 
					 * @Describe WinBoLLActivity
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					import android.app.Activity;
 | 
				
			||||||
 | 
					import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class WinBoLLActivity extends Activity implements IWinBoLLActivity {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static final String TAG = "WinBoLLActivity";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Activity getActivity() {
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String getTag() {
 | 
				
			||||||
 | 
					        return TAG;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										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/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### 参考文档
 | 
				
			||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
#Created by .winboll/winboll_app_build.gradle
 | 
					#Created by .winboll/winboll_app_build.gradle
 | 
				
			||||||
#Sun May 04 05:32:00 GMT 2025
 | 
					#Tue Jun 24 09:54:47 HKT 2025
 | 
				
			||||||
stageCount=1
 | 
					stageCount=3
 | 
				
			||||||
libraryProject=
 | 
					libraryProject=
 | 
				
			||||||
baseVersion=15.2
 | 
					baseVersion=15.2
 | 
				
			||||||
publishVersion=15.2.0
 | 
					publishVersion=15.2.2
 | 
				
			||||||
buildCount=74
 | 
					buildCount=0
 | 
				
			||||||
baseBetaVersion=15.2.1
 | 
					baseBetaVersion=15.2.3
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.autoinstaller;
 | 
					package cc.winboll.studio.autoinstaller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/04/28 02:39:58
 | 
					 * @Date 2024/04/28 02:39:58
 | 
				
			||||||
 * @Describe 全局应用类
 | 
					 * @Describe 全局应用类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.autoinstaller;
 | 
					package cc.winboll.studio.autoinstaller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/04/15 09:24:46
 | 
					 * @Date 2025/04/15 09:24:46
 | 
				
			||||||
 * @Describe 磁贴工具服务类
 | 
					 * @Describe 磁贴工具服务类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.autoinstaller.models;
 | 
					package cc.winboll.studio.autoinstaller.models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/04/02 20:50:29
 | 
					 * @Date 2025/04/02 20:50:29
 | 
				
			||||||
 * @Describe 监控的 APK 安装文件对应的应用信息数据模型
 | 
					 * @Describe 监控的 APK 安装文件对应的应用信息数据模型
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.autoinstaller.models;
 | 
					package cc.winboll.studio.autoinstaller.models;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/05/27 17:36:01
 | 
					 * @Date 2024/05/27 17:36:01
 | 
				
			||||||
 * @Describe 应用配置数据类
 | 
					 * @Describe 应用配置数据类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ import cc.winboll.studio.libappbase.BaseBean;
 | 
				
			|||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/04/15 09:27:39
 | 
					 * @Date 2025/04/15 09:27:39
 | 
				
			||||||
 * @Describe MainServiceBean
 | 
					 * @Describe MainServiceBean
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ import cc.winboll.studio.autoinstaller.services.MainService;
 | 
				
			|||||||
import cc.winboll.studio.libappbase.LogUtils;
 | 
					import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/06/06 13:19:38
 | 
					 * @Date 2024/06/06 13:19:38
 | 
				
			||||||
 * @Describe 应用消息接收类
 | 
					 * @Describe 应用消息接收类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ import cc.winboll.studio.autoinstaller.models.AppConfigs;
 | 
				
			|||||||
import cc.winboll.studio.autoinstaller.utils.ServiceUtil;
 | 
					import cc.winboll.studio.autoinstaller.utils.ServiceUtil;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/05/27 20:16:00
 | 
					 * @Date 2024/05/27 20:16:00
 | 
				
			||||||
 * @Describe MainService 守护进程服务
 | 
					 * @Describe MainService 守护进程服务
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.autoinstaller.utils;
 | 
					package cc.winboll.studio.autoinstaller.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/05/27 17:56:31
 | 
					 * @Date 2024/05/27 17:56:31
 | 
				
			||||||
 * @Describe 文件管理类
 | 
					 * @Describe 文件管理类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.autoinstaller.utils;
 | 
					package cc.winboll.studio.autoinstaller.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/12/11 06:28:50
 | 
					 * @Date 2024/12/11 06:28:50
 | 
				
			||||||
 * @Describe 一个获取安卓APK安装文件的应用包名的函数
 | 
					 * @Describe 一个获取安卓APK安装文件的应用包名的函数
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.autoinstaller.utils;
 | 
					package cc.winboll.studio.autoinstaller.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/05/27 20:20:03
 | 
					 * @Date 2024/05/27 20:20:03
 | 
				
			||||||
 * @Describe 服务类工具
 | 
					 * @Describe 服务类工具
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,7 +72,7 @@ allprojects {
 | 
				
			|||||||
        bashCommitAppPublishBuildFlagInfoFilePath = ".winboll/bashCommitAppPublishBuildFlagInfo.sh"
 | 
					        bashCommitAppPublishBuildFlagInfoFilePath = ".winboll/bashCommitAppPublishBuildFlagInfo.sh"
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        winbollFilePath = "winboll.properties"
 | 
					        winbollFilePath = "winboll.properties"
 | 
				
			||||||
        keyPropsFilePath = "current.keystore"
 | 
					        keyPropsFilePath = "appkey.keystore"
 | 
				
			||||||
        // 定义 lint 输出文件
 | 
					        // 定义 lint 输出文件
 | 
				
			||||||
        lintXmlReportFilePath = "build/reports/lint-results.xml"
 | 
					        lintXmlReportFilePath = "build/reports/lint-results.xml"
 | 
				
			||||||
        lintHTMLReportFilePath = "build/reports/lint-results.html"
 | 
					        lintHTMLReportFilePath = "build/reports/lint-results.html"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
https://github.com/aJIEw/PhoneCallApp.git
 | 
					https://github.com/aJIEw/PhoneCallApp.git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### 介绍
 | 
					#### 介绍
 | 
				
			||||||
通讯录与拨号
 | 
					这是可以根据正则表达式匹配拦截骚扰电话的手机拨号应用。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### 软件架构
 | 
					#### 软件架构
 | 
				
			||||||
适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。
 | 
					适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,12 +24,12 @@ android {
 | 
				
			|||||||
    defaultConfig {
 | 
					    defaultConfig {
 | 
				
			||||||
        applicationId "cc.winboll.studio.contacts"
 | 
					        applicationId "cc.winboll.studio.contacts"
 | 
				
			||||||
        minSdkVersion 24
 | 
					        minSdkVersion 24
 | 
				
			||||||
        targetSdkVersion 29
 | 
					        targetSdkVersion 30
 | 
				
			||||||
        versionCode 1
 | 
					        versionCode 1
 | 
				
			||||||
        // versionName 更新后需要手动设置 
 | 
					        // versionName 更新后需要手动设置 
 | 
				
			||||||
        // 项目模块目录的 build.gradle 文件的 stageCount=0
 | 
					        // 项目模块目录的 build.gradle 文件的 stageCount=0
 | 
				
			||||||
        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
					        // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
 | 
				
			||||||
        versionName "15.2" 
 | 
					        versionName "15.3" 
 | 
				
			||||||
        if(true) {
 | 
					        if(true) {
 | 
				
			||||||
            versionName = genVersionName("${versionName}")
 | 
					            versionName = genVersionName("${versionName}")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -45,6 +45,9 @@ android {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
dependencies {
 | 
					dependencies {
 | 
				
			||||||
    api fileTree(dir: 'libs', include: ['*.jar'])
 | 
					    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
 | 
					    // 权限请求框架:https://github.com/getActivity/XXPermissions
 | 
				
			||||||
    api 'com.github.getActivity:XXPermissions:18.63'
 | 
					    api 'com.github.getActivity:XXPermissions:18.63'
 | 
				
			||||||
@@ -81,8 +84,4 @@ dependencies {
 | 
				
			|||||||
    //api 'androidx.vectordrawable:vectordrawable:1.1.0'
 | 
					    //api 'androidx.vectordrawable:vectordrawable:1.1.0'
 | 
				
			||||||
    //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
 | 
					    //api 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
 | 
				
			||||||
    //api 'androidx.fragment:fragment: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
 | 
					#Created by .winboll/winboll_app_build.gradle
 | 
				
			||||||
#Sun Apr 13 02:46:09 HKT 2025
 | 
					#Sun Aug 31 06:05:42 CST 2025
 | 
				
			||||||
stageCount=8
 | 
					stageCount=17
 | 
				
			||||||
libraryProject=
 | 
					libraryProject=
 | 
				
			||||||
baseVersion=15.2
 | 
					baseVersion=15.3
 | 
				
			||||||
publishVersion=15.2.7
 | 
					publishVersion=15.3.16
 | 
				
			||||||
buildCount=0
 | 
					buildCount=0
 | 
				
			||||||
baseBetaVersion=15.2.8
 | 
					baseBetaVersion=15.3.17
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,7 +42,8 @@
 | 
				
			|||||||
        android:icon="@drawable/ic_winboll"
 | 
					        android:icon="@drawable/ic_winboll"
 | 
				
			||||||
        android:label="@string/app_name"
 | 
					        android:label="@string/app_name"
 | 
				
			||||||
        android:theme="@style/MyAppTheme"
 | 
					        android:theme="@style/MyAppTheme"
 | 
				
			||||||
        android:supportsRtl="true">
 | 
					        android:supportsRtl="true"
 | 
				
			||||||
 | 
					        android:networkSecurityConfig="@xml/network_security_config">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <activity
 | 
					        <activity
 | 
				
			||||||
            android:name=".MainActivity"
 | 
					            android:name=".MainActivity"
 | 
				
			||||||
@@ -192,4 +193,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    </application>
 | 
					    </application>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</manifest>
 | 
					</manifest>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts;
 | 
					package cc.winboll.studio.contacts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2024/12/08 15:10:51
 | 
					 * @Date 2024/12/08 15:10:51
 | 
				
			||||||
 * @Describe 全局应用类
 | 
					 * @Describe 全局应用类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.view.Gravity;
 | 
					import android.view.Gravity;
 | 
				
			||||||
import cc.winboll.studio.libappbase.GlobalApplication;
 | 
					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;
 | 
					import com.hjq.toast.ToastUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class App extends GlobalApplication {
 | 
					public class App extends GlobalApplication {
 | 
				
			||||||
@@ -20,8 +20,8 @@ public class App extends GlobalApplication {
 | 
				
			|||||||
        // 这样可以预先设置日志与数据的存储根目录。
 | 
					        // 这样可以预先设置日志与数据的存储根目录。
 | 
				
			||||||
        //setIsDebuging(BuildConfig.DEBUG);
 | 
					        //setIsDebuging(BuildConfig.DEBUG);
 | 
				
			||||||
        super.onCreate();
 | 
					        super.onCreate();
 | 
				
			||||||
        // 设置 WinBoll 应用 UI 类型
 | 
					        // 设置 WinBoLL 应用 UI 类型
 | 
				
			||||||
        WinBollActivityManager.getInstance(this).setWinBollUI_TYPE(WinBollActivityManager.WinBollUI_TYPE.Aplication);
 | 
					        getWinBoLLActivityManager().setWinBoLLUI_TYPE(WinBoLLActivityManager.WinBoLLUI_TYPE.Aplication);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        //LogUtils.d(TAG, "onCreate");
 | 
					        //LogUtils.d(TAG, "onCreate");
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,10 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts;
 | 
					package cc.winboll.studio.contacts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
 | 
				
			||||||
 | 
					 * @Date 2025/08/30 14:32
 | 
				
			||||||
 | 
					 * @Describe 主窗口
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
import android.Manifest;
 | 
					import android.Manifest;
 | 
				
			||||||
import android.app.Activity;
 | 
					import android.app.Activity;
 | 
				
			||||||
import android.app.ActivityManager;
 | 
					import android.app.ActivityManager;
 | 
				
			||||||
@@ -8,6 +13,7 @@ import android.content.Intent;
 | 
				
			|||||||
import android.content.pm.PackageManager;
 | 
					import android.content.pm.PackageManager;
 | 
				
			||||||
import android.os.Build;
 | 
					import android.os.Build;
 | 
				
			||||||
import android.os.Bundle;
 | 
					import android.os.Bundle;
 | 
				
			||||||
 | 
					import android.os.Handler;
 | 
				
			||||||
import android.telecom.TelecomManager;
 | 
					import android.telecom.TelecomManager;
 | 
				
			||||||
import android.telephony.PhoneStateListener;
 | 
					import android.telephony.PhoneStateListener;
 | 
				
			||||||
import android.telephony.TelephonyManager;
 | 
					import android.telephony.TelephonyManager;
 | 
				
			||||||
@@ -32,22 +38,21 @@ import cc.winboll.studio.contacts.fragments.CallLogFragment;
 | 
				
			|||||||
import cc.winboll.studio.contacts.fragments.ContactsFragment;
 | 
					import cc.winboll.studio.contacts.fragments.ContactsFragment;
 | 
				
			||||||
import cc.winboll.studio.contacts.fragments.LogFragment;
 | 
					import cc.winboll.studio.contacts.fragments.LogFragment;
 | 
				
			||||||
import cc.winboll.studio.contacts.services.MainService;
 | 
					import cc.winboll.studio.contacts.services.MainService;
 | 
				
			||||||
import cc.winboll.studio.libaes.winboll.APPInfo;
 | 
					 | 
				
			||||||
import cc.winboll.studio.libappbase.LogUtils;
 | 
					import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			||||||
import cc.winboll.studio.libappbase.LogView;
 | 
					import cc.winboll.studio.libappbase.LogView;
 | 
				
			||||||
import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
 | 
					import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
 | 
				
			||||||
import com.google.android.material.tabs.TabLayout;
 | 
					import com.google.android.material.tabs.TabLayout;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
final public class MainActivity extends AppCompatActivity implements IWinBollActivity, ViewPager.OnPageChangeListener, View.OnClickListener {
 | 
					final public class MainActivity extends AppCompatActivity implements IWinBoLLActivity, ViewPager.OnPageChangeListener, View.OnClickListener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public static final String TAG = "MainActivity";
 | 
					    public static final String TAG = "MainActivity";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static final int REQUEST_HOME_ACTIVITY = 0;
 | 
					    public static final int REQUEST_HOME_ACTIVITY = 0;
 | 
				
			||||||
    public static final int REQUEST_ABOUT_ACTIVITY = 1;
 | 
					    public static final int REQUEST_ABOUT_ACTIVITY = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static final String ACTION_SOS = "cc.winboll.studio.libappbase.WinBoll.ACTION_SOS";
 | 
					    public static final String ACTION_SOS = "cc.winboll.studio.libappbase.WinBoLL.ACTION_SOS";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static MainActivity _MainActivity;
 | 
					    static MainActivity _MainActivity;
 | 
				
			||||||
    LogView mLogView;
 | 
					    LogView mLogView;
 | 
				
			||||||
@@ -56,13 +61,10 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
 | 
				
			|||||||
    MainServiceBean mMainServiceBean;
 | 
					    MainServiceBean mMainServiceBean;
 | 
				
			||||||
    private TabLayout tabLayout;
 | 
					    private TabLayout tabLayout;
 | 
				
			||||||
    private ViewPager viewPager;
 | 
					    private ViewPager viewPager;
 | 
				
			||||||
    private List<View> views; //用来存放放进ViewPager里面的布局
 | 
					    private List<View> views; 
 | 
				
			||||||
    //实例化存储imageView(导航原点)的集合
 | 
					 | 
				
			||||||
    ImageView[] imageViews;
 | 
					    ImageView[] imageViews;
 | 
				
			||||||
    //MyPagerAdapter adapter;//适配器
 | 
					    LinearLayout linearLayout;
 | 
				
			||||||
    MyPagerAdapter pagerAdapter;
 | 
					    int currentPoint = 0;
 | 
				
			||||||
    LinearLayout linearLayout;//下标所在在LinearLayout布局里
 | 
					 | 
				
			||||||
    int currentPoint = 0;//当前被选中中页面的下标
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private TelephonyManager telephonyManager;
 | 
					    private TelephonyManager telephonyManager;
 | 
				
			||||||
    private MyPhoneStateListener phoneStateListener;
 | 
					    private MyPhoneStateListener phoneStateListener;
 | 
				
			||||||
@@ -71,115 +73,75 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private static final int DIALER_REQUEST_CODE = 1;
 | 
					    private static final int DIALER_REQUEST_CODE = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Activity getActivity() {
 | 
					    public Activity getActivity() {
 | 
				
			||||||
        return this;
 | 
					        return this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//    @Override
 | 
					    @Override
 | 
				
			||||||
//    public APPInfo getAppInfo() {
 | 
					    public String getTag() {
 | 
				
			||||||
//        String szBranchName = "contacts";
 | 
					        return TAG;
 | 
				
			||||||
//
 | 
					    }
 | 
				
			||||||
//        APPInfo appInfo = AboutActivityFactory.buildDefaultAPPInfo();
 | 
					 | 
				
			||||||
//        appInfo.setAppName("Contacts");
 | 
					 | 
				
			||||||
//        appInfo.setAppIcon(cc.winboll.studio.libapputils.R.drawable.ic_winboll);
 | 
					 | 
				
			||||||
//        appInfo.setAppDescription("Contacts Description");
 | 
					 | 
				
			||||||
//        appInfo.setAppGitName("APP");
 | 
					 | 
				
			||||||
//        appInfo.setAppGitOwner("Studio");
 | 
					 | 
				
			||||||
//        appInfo.setAppGitAPPBranch(szBranchName);
 | 
					 | 
				
			||||||
//        appInfo.setAppGitAPPSubProjectFolder(szBranchName);
 | 
					 | 
				
			||||||
//        appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=Contacts");
 | 
					 | 
				
			||||||
//        appInfo.setAppAPKName("Contacts");
 | 
					 | 
				
			||||||
//        appInfo.setAppAPKFolderName("Contacts");
 | 
					 | 
				
			||||||
//        return appInfo;
 | 
					 | 
				
			||||||
//        return null;
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected void onCreate(Bundle savedInstanceState) {
 | 
					    protected void onCreate(Bundle savedInstanceState) {
 | 
				
			||||||
        // 接收并处理 Intent 数据,函数 Intent 处理接收就直接返回
 | 
					 | 
				
			||||||
        //if (prosessIntents(getIntent())) return;
 | 
					 | 
				
			||||||
        // 以下正常创建主窗口
 | 
					 | 
				
			||||||
        super.onCreate(savedInstanceState);
 | 
					        super.onCreate(savedInstanceState);
 | 
				
			||||||
        _MainActivity = this;
 | 
					        _MainActivity = this;
 | 
				
			||||||
        setContentView(R.layout.activity_main);
 | 
					        setContentView(R.layout.activity_main);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 初始化工具栏
 | 
					        // 初始化工具栏(仅加载基础UI)
 | 
				
			||||||
        mToolbar = findViewById(R.id.activitymainToolbar1);
 | 
					        mToolbar = (Toolbar) findViewById(R.id.activitymainToolbar1);
 | 
				
			||||||
        setSupportActionBar(mToolbar);
 | 
					        setSupportActionBar(mToolbar);
 | 
				
			||||||
//        if (isEnableDisplayHomeAsUp()) {
 | 
					        getSupportActionBar().setSubtitle(TAG);
 | 
				
			||||||
//            // 显示后退按钮
 | 
					 | 
				
			||||||
//            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
 | 
					 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
        getSupportActionBar().setSubtitle(getTag());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        tabLayout = findViewById(R.id.tabLayout);
 | 
					        tabLayout = (TabLayout) findViewById(R.id.tabLayout);
 | 
				
			||||||
        viewPager = findViewById(R.id.viewPager);
 | 
					        viewPager = (ViewPager) findViewById(R.id.viewPager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 创建Fragment列表和标题列表
 | 
					        // 创建Fragment列表(仅实例化,不加载数据)
 | 
				
			||||||
        fragmentList = new ArrayList<>();
 | 
					        fragmentList = new ArrayList<Fragment>();
 | 
				
			||||||
        tabTitleList = new ArrayList<>();
 | 
					        tabTitleList = new ArrayList<String>();
 | 
				
			||||||
        fragmentList.add(CallLogFragment.newInstance(0));
 | 
					        fragmentList.add(CallLogFragment.newInstance(0));
 | 
				
			||||||
        fragmentList.add(ContactsFragment.newInstance(1));
 | 
					        fragmentList.add(ContactsFragment.newInstance(1)); // 延迟加载联系人数据
 | 
				
			||||||
        fragmentList.add(LogFragment.newInstance(2));
 | 
					        fragmentList.add(LogFragment.newInstance(2));
 | 
				
			||||||
        tabTitleList.add("通话记录");
 | 
					        tabTitleList.add("通话记录");
 | 
				
			||||||
        tabTitleList.add("联系人");
 | 
					        tabTitleList.add("联系人");
 | 
				
			||||||
        tabTitleList.add("应用日志");
 | 
					        tabTitleList.add("应用日志");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 设置ViewPager的适配器
 | 
					        // 设置ViewPager适配器
 | 
				
			||||||
        MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager(), fragmentList, tabTitleList);
 | 
					        MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager(), fragmentList, tabTitleList);
 | 
				
			||||||
        viewPager.setAdapter(adapter);
 | 
					        viewPager.setAdapter(adapter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 关键:关闭预加载,仅当前页初始化
 | 
				
			||||||
 | 
					        viewPager.setOffscreenPageLimit(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 关联TabLayout和ViewPager
 | 
					        // 关联TabLayout和ViewPager
 | 
				
			||||||
        tabLayout.setupWithViewPager(viewPager);
 | 
					        tabLayout.setupWithViewPager(viewPager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 初始化服务状态(延迟启动非核心服务)
 | 
				
			||||||
 | 
					 | 
				
			||||||
//        initData();
 | 
					 | 
				
			||||||
//        initView();
 | 
					 | 
				
			||||||
//        //initPoint();//调用初始化导航原点的方法
 | 
					 | 
				
			||||||
//        viewPager.addOnPageChangeListener(this);//滑动事件
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //ViewPager viewPager = findViewById(R.id.activitymainViewPager1);
 | 
					 | 
				
			||||||
        //MyPagerAdapter pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
 | 
					 | 
				
			||||||
        //viewPager.setAdapter(pagerAdapter);
 | 
					 | 
				
			||||||
        //TabLayout tabLayout = findViewById(R.id.activitymainTabLayout1);
 | 
					 | 
				
			||||||
        //tabLayout.setupWithViewPager(viewPager);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//        mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
 | 
					 | 
				
			||||||
//        if (mMainServiceBean == null) {
 | 
					 | 
				
			||||||
//            mMainServiceBean = new MainServiceBean();
 | 
					 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
//        cbMainService = findViewById(R.id.activitymainCheckBox1);
 | 
					 | 
				
			||||||
//        cbMainService.setChecked(mMainServiceBean.isEnable());
 | 
					 | 
				
			||||||
//        cbMainService.setOnClickListener(new View.OnClickListener(){
 | 
					 | 
				
			||||||
//                @Override
 | 
					 | 
				
			||||||
//                public void onClick(View view) {
 | 
					 | 
				
			||||||
//                    if (cbMainService.isChecked()) {
 | 
					 | 
				
			||||||
//                        MainService.startMainService(MainActivity.this);
 | 
					 | 
				
			||||||
//                    } else {
 | 
					 | 
				
			||||||
//                        MainService.stopMainService(MainActivity.this);
 | 
					 | 
				
			||||||
//                    }
 | 
					 | 
				
			||||||
//                }
 | 
					 | 
				
			||||||
//            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        MainServiceBean mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
 | 
					        MainServiceBean mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
 | 
				
			||||||
        if (mMainServiceBean == null) {
 | 
					        if (mMainServiceBean == null) {
 | 
				
			||||||
            mMainServiceBean = new MainServiceBean();
 | 
					            mMainServiceBean = new MainServiceBean();
 | 
				
			||||||
            MainServiceBean.saveBean(this, mMainServiceBean);
 | 
					            MainServiceBean.saveBean(this, mMainServiceBean);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (mMainServiceBean.isEnable()) {
 | 
					        if (mMainServiceBean.isEnable()) {
 | 
				
			||||||
            MainService.startMainService(this);
 | 
					            // 延迟1秒启动服务,避免阻塞启动
 | 
				
			||||||
 | 
					            new Handler().postDelayed(new Runnable() {
 | 
				
			||||||
 | 
										@Override
 | 
				
			||||||
 | 
										public void run() {
 | 
				
			||||||
 | 
											MainService.startMainService(MainActivity.this);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}, 1000);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 初始化TelephonyManager和PhoneStateListener
 | 
					        // 初始化电话状态监听(基础功能保留)
 | 
				
			||||||
        telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
 | 
					        telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
 | 
				
			||||||
        phoneStateListener = new MyPhoneStateListener();
 | 
					        phoneStateListener = new MyPhoneStateListener();
 | 
				
			||||||
        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
 | 
					        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // ViewPager的适配器
 | 
					    // ViewPager适配器(Java 7语法)
 | 
				
			||||||
    private class MyPagerAdapter extends FragmentPagerAdapter {
 | 
					    private class MyPagerAdapter extends FragmentPagerAdapter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private List<Fragment> fragmentList;
 | 
					        private List<Fragment> fragmentList;
 | 
				
			||||||
@@ -216,91 +178,22 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
 | 
				
			|||||||
        _MainActivity.startActivity(intent);
 | 
					        _MainActivity.startActivity(intent);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //初始化view,即显示的图片
 | 
					    // OnPageChangeListener接口实现
 | 
				
			||||||
//    void initView() {
 | 
					 | 
				
			||||||
//        viewPager = findViewById(R.id.activitymainViewPager1);
 | 
					 | 
				
			||||||
//        pagerAdapter = new MyPagerAdapter(getSupportFragmentManager());
 | 
					 | 
				
			||||||
//        viewPager.setAdapter(pagerAdapter);
 | 
					 | 
				
			||||||
//        //adapter = new MyPagerAdapter(views);
 | 
					 | 
				
			||||||
//        //viewPager = findViewById(R.id.activitymainViewPager1);
 | 
					 | 
				
			||||||
//        //viewPager.setAdapter(adapter);
 | 
					 | 
				
			||||||
//        //linearLayout = findViewById(R.id.activitymainLinearLayout1);
 | 
					 | 
				
			||||||
//        //initPoint();//初始化页面下方的点
 | 
					 | 
				
			||||||
//        viewPager.setOnPageChangeListener(this);
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //初始化所要显示的布局
 | 
					 | 
				
			||||||
//    void initData() {
 | 
					 | 
				
			||||||
//        LayoutInflater inflater = LayoutInflater.from(getActivity());
 | 
					 | 
				
			||||||
//        View view1 = inflater.inflate(R.layout.fragment_call_log, viewPager, false);
 | 
					 | 
				
			||||||
//        View view2 = inflater.inflate(R.layout.fragment_contacts, viewPager, false);
 | 
					 | 
				
			||||||
//        View view3 = inflater.inflate(R.layout.fragment_log, viewPager, false);
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//        views = new ArrayList<>();
 | 
					 | 
				
			||||||
//        views.add(view1);
 | 
					 | 
				
			||||||
//        views.add(view2);
 | 
					 | 
				
			||||||
//        views.add(view3);
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//    void initPoint() {
 | 
					 | 
				
			||||||
//        imageViews = new ImageView[5];//实例化5个图片
 | 
					 | 
				
			||||||
//        for (int i = 0; i < linearLayout.getChildCount(); i++) {
 | 
					 | 
				
			||||||
//            imageViews[i] = (ImageView) linearLayout.getChildAt(i);
 | 
					 | 
				
			||||||
//            imageViews[i].setImageResource(R.drawable.ic_launcher);
 | 
					 | 
				
			||||||
//            imageViews[i].setOnClickListener(this);//点击导航点,即可跳转
 | 
					 | 
				
			||||||
//            imageViews[i].setTag(i);//重复利用实例化的对象
 | 
					 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
//        currentPoint = 0;//默认第一个坐标
 | 
					 | 
				
			||||||
//        imageViews[currentPoint].setImageResource(R.drawable.ic_launcher);
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //OnPageChangeListener接口要实现的三个方法
 | 
					 | 
				
			||||||
    /*    onPageScrollStateChanged(int state)
 | 
					 | 
				
			||||||
     此方法是在状态改变的时候调用,其中state这个参数有三种状态:
 | 
					 | 
				
			||||||
     SCROLL_STATE_DRAGGING(1)表示用户手指“按在屏幕上并且开始拖动”的状态
 | 
					 | 
				
			||||||
     (手指按下但是还没有拖动的时候还不是这个状态,只有按下并且手指开始拖动后log才打出。)
 | 
					 | 
				
			||||||
     SCROLL_STATE_IDLE(0)滑动动画做完的状态。
 | 
					 | 
				
			||||||
     SCROLL_STATE_SETTLING(2)在“手指离开屏幕”的状态。*/
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onPageScrollStateChanged(int state) {
 | 
					    public void onPageScrollStateChanged(int state) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /*    onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
 | 
					 | 
				
			||||||
     当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。其中三个参数的含义分别为:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     position :当前页面,即你点击滑动的页面(从A滑B,则是A页面的position。
 | 
					 | 
				
			||||||
     positionOffset:当前页面偏移的百分比
 | 
					 | 
				
			||||||
     positionOffsetPixels:当前页面偏移的像素位置*/
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
 | 
					    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /*    onPageSelected(int position)
 | 
					 | 
				
			||||||
     此方法是页面滑动完后得到调用,position是你当前选中的页面的Position(位置编号)
 | 
					 | 
				
			||||||
     (从A滑动到B,就是B的position)*/
 | 
					 | 
				
			||||||
    public void onPageSelected(int position) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//        ImageView preView = imageViews[currentPoint];
 | 
					 | 
				
			||||||
//        preView.setImageResource(R.drawable.ic_launcher);
 | 
					 | 
				
			||||||
//        ImageView currView = imageViews[position];
 | 
					 | 
				
			||||||
//        currView.setImageResource(R.drawable.ic_launcher);
 | 
					 | 
				
			||||||
//        currentPoint = position;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //小圆点点击事件
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onClick(View v) {
 | 
					    public void onPageSelected(int position) {}
 | 
				
			||||||
        // TODO Auto-generated method stub
 | 
					
 | 
				
			||||||
        //通过getTag(),可以判断是哪个控件
 | 
					    @Override
 | 
				
			||||||
//        int i = (Integer) v.getTag();
 | 
					    public void onClick(View v) {}
 | 
				
			||||||
//        viewPager.setCurrentItem(i);//直接跳转到某一个页面的情况
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected void onPostCreate(Bundle savedInstanceState) {
 | 
					    protected void onPostCreate(Bundle savedInstanceState) {
 | 
				
			||||||
        super.onPostCreate(savedInstanceState);
 | 
					        super.onPostCreate(savedInstanceState);
 | 
				
			||||||
        //setSubTitle("");
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private class MyPhoneStateListener extends PhoneStateListener {
 | 
					    private class MyPhoneStateListener extends PhoneStateListener {
 | 
				
			||||||
@@ -326,109 +219,31 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
 | 
				
			|||||||
        LogUtils.d(TAG, "onDestroy() SOS");
 | 
					        LogUtils.d(TAG, "onDestroy() SOS");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    // 处理传入的 Intent 数据
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
//    boolean prosessIntents(Intent intent) {
 | 
					 | 
				
			||||||
//        if (intent == null 
 | 
					 | 
				
			||||||
//            || intent.getAction() == null
 | 
					 | 
				
			||||||
//            || intent.getAction().equals(""))
 | 
					 | 
				
			||||||
//            return false;
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//        if (intent.getAction().equals(StringToQrCodeView.ACTION_UNITTEST_QRCODE)) {
 | 
					 | 
				
			||||||
//            try {
 | 
					 | 
				
			||||||
//                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);
 | 
					 | 
				
			||||||
//                subIntent.setAction(intent.getAction());
 | 
					 | 
				
			||||||
//                File file = new File(getCacheDir(), UUID.randomUUID().toString());
 | 
					 | 
				
			||||||
//                //取出文件uri
 | 
					 | 
				
			||||||
//                Uri uri = intent.getData();
 | 
					 | 
				
			||||||
//                if (uri == null) {
 | 
					 | 
				
			||||||
//                    uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
 | 
					 | 
				
			||||||
//                }
 | 
					 | 
				
			||||||
//                //获取文件真实地址
 | 
					 | 
				
			||||||
//                String szSrcPath = UriUtils.getFileFromUri(getApplication(), uri);
 | 
					 | 
				
			||||||
//                if (TextUtils.isEmpty(szSrcPath)) {
 | 
					 | 
				
			||||||
//                    return false;
 | 
					 | 
				
			||||||
//                }
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//                Files.copy(Paths.get(szSrcPath), Paths.get(file.getPath()));
 | 
					 | 
				
			||||||
//                //startWinBollActivity(subIntent, tag);
 | 
					 | 
				
			||||||
//                WinBollActivityManager.getInstance(this).startWinBollActivity(this, subIntent, UnitTestActivity.class);
 | 
					 | 
				
			||||||
//            } catch (IllegalAccessException | InstantiationException | IOException e) {
 | 
					 | 
				
			||||||
//                LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
 | 
					 | 
				
			||||||
//                // 函数处理异常返回失败
 | 
					 | 
				
			||||||
//                return false;
 | 
					 | 
				
			||||||
//            }
 | 
					 | 
				
			||||||
//        } else {
 | 
					 | 
				
			||||||
//            LogUtils.d(TAG, "prosessIntents|" + intent.getAction() + "|yet");
 | 
					 | 
				
			||||||
//            return false;
 | 
					 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
//        return true;
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public String getTag() {
 | 
					 | 
				
			||||||
        return TAG;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//    @Override
 | 
					 | 
				
			||||||
//    public void onBackPressed() {
 | 
					 | 
				
			||||||
//        exit();
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//    void exit() {
 | 
					 | 
				
			||||||
//        YesNoAlertDialog.OnDialogResultListener listener = new YesNoAlertDialog.OnDialogResultListener(){
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//            @Override
 | 
					 | 
				
			||||||
//            public void onYes() {
 | 
					 | 
				
			||||||
//                WinBollActivityManager.getInstance(getApplicationContext()).finishAll();
 | 
					 | 
				
			||||||
//            }
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
//            @Override
 | 
					 | 
				
			||||||
//            public void onNo() {
 | 
					 | 
				
			||||||
//            }
 | 
					 | 
				
			||||||
//        };
 | 
					 | 
				
			||||||
//        YesNoAlertDialog.show(this, "[ " + getString(R.string.app_name) + " ]", "Exit(Yes/No).\nIs close all activity?", listener);
 | 
					 | 
				
			||||||
//    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onCreateOptionsMenu(Menu menu) {
 | 
					    public boolean onCreateOptionsMenu(Menu menu) {
 | 
				
			||||||
        getMenuInflater().inflate(R.menu.toolbar_main, menu);
 | 
					        getMenuInflater().inflate(R.menu.toolbar_main, menu);
 | 
				
			||||||
        return super.onCreateOptionsMenu(menu);
 | 
					        return super.onCreateOptionsMenu(menu);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public boolean onOptionsItemSelected(MenuItem item) {
 | 
					    public boolean onOptionsItemSelected(MenuItem item) {
 | 
				
			||||||
        if (item.getItemId() == R.id.item_settings) {
 | 
					        if (item.getItemId() == R.id.item_settings) {
 | 
				
			||||||
            Intent intent = new Intent(this, SettingsActivity.class);
 | 
					            Intent intent = new Intent(this, SettingsActivity.class);
 | 
				
			||||||
            startActivity(intent);
 | 
					            startActivity(intent);
 | 
				
			||||||
            //WinBollActivityManager.getInstance(this).startWinBollActivity(this, CallActivity.class);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
//        } else 
 | 
					 | 
				
			||||||
//        if (item.getItemId() == R.id.item_exit) {
 | 
					 | 
				
			||||||
//            exit();
 | 
					 | 
				
			||||||
//            return true;
 | 
					 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
        return super.onOptionsItemSelected(item);
 | 
					        return super.onOptionsItemSelected(item);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected void onResume() {
 | 
					    protected void onResume() {
 | 
				
			||||||
        super.onResume();
 | 
					        super.onResume();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Android M 及以上检查是否是系统默认电话应用
 | 
					     * 检查是否是系统默认电话应用
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public boolean isDefaultPhoneCallApp() {
 | 
					    public boolean isDefaultPhoneCallApp() {
 | 
				
			||||||
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 | 
					        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 | 
				
			||||||
            TelecomManager manger = (TelecomManager) getSystemService(TELECOM_SERVICE);
 | 
					            TelecomManager manger = (TelecomManager) getSystemService(TELECOM_SERVICE);
 | 
				
			||||||
            if (manger != null && manger.getDefaultDialerPackage() != null) {
 | 
					            if (manger != null && manger.getDefaultDialerPackage() != null) {
 | 
				
			||||||
                return manger.getDefaultDialerPackage().equals(getPackageName());
 | 
					                return manger.getDefaultDialerPackage().equals(getPackageName());
 | 
				
			||||||
@@ -442,35 +257,22 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
 | 
				
			|||||||
        if (manager == null) return false;
 | 
					        if (manager == null) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
 | 
					        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
 | 
				
			||||||
            Integer.MAX_VALUE)) {
 | 
								Integer.MAX_VALUE)) {
 | 
				
			||||||
            if (serviceClass.getName().equals(service.service.getClassName())) {
 | 
					            if (serviceClass.getName().equals(service.service.getClassName())) {
 | 
				
			||||||
                return true;
 | 
					                return true;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 | 
					    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 | 
				
			||||||
//        switch (resultCode) {
 | 
					 | 
				
			||||||
//            case REQUEST_HOME_ACTIVITY : {
 | 
					 | 
				
			||||||
//                    LogUtils.d(TAG, "REQUEST_HOME_ACTIVITY");
 | 
					 | 
				
			||||||
//                    break;
 | 
					 | 
				
			||||||
//                }
 | 
					 | 
				
			||||||
//            case REQUEST_ABOUT_ACTIVITY : {
 | 
					 | 
				
			||||||
//                    LogUtils.d(TAG, "REQUEST_ABOUT_ACTIVITY");
 | 
					 | 
				
			||||||
//                    break;
 | 
					 | 
				
			||||||
//                }
 | 
					 | 
				
			||||||
//            default : {
 | 
					 | 
				
			||||||
//                    super.onActivityResult(requestCode, resultCode, data);
 | 
					 | 
				
			||||||
//                }
 | 
					 | 
				
			||||||
//        }
 | 
					 | 
				
			||||||
        if (requestCode == DIALER_REQUEST_CODE) {
 | 
					        if (requestCode == DIALER_REQUEST_CODE) {
 | 
				
			||||||
            if (resultCode == Activity.RESULT_OK) {
 | 
					            if (resultCode == Activity.RESULT_OK) {
 | 
				
			||||||
                Toast.makeText(MainActivity.this, getString(R.string.app_name) + " 已成为默认电话应用",
 | 
					                Toast.makeText(MainActivity.this, getString(R.string.app_name) + " 已成为默认电话应用",
 | 
				
			||||||
                               Toast.LENGTH_SHORT).show();
 | 
												   Toast.LENGTH_SHORT).show();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.activities;
 | 
					package cc.winboll.studio.contacts.activities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/31 15:15:54
 | 
					 * @Date 2025/03/31 15:15:54
 | 
				
			||||||
 * @Describe 应用介绍窗口
 | 
					 * @Describe 应用介绍窗口
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -10,14 +10,15 @@ import android.content.Context;
 | 
				
			|||||||
import android.os.Bundle;
 | 
					import android.os.Bundle;
 | 
				
			||||||
import android.view.ViewGroup;
 | 
					import android.view.ViewGroup;
 | 
				
			||||||
import android.widget.LinearLayout;
 | 
					import android.widget.LinearLayout;
 | 
				
			||||||
 | 
					import androidx.appcompat.app.AppCompatActivity;
 | 
				
			||||||
import androidx.appcompat.widget.Toolbar;
 | 
					import androidx.appcompat.widget.Toolbar;
 | 
				
			||||||
import cc.winboll.studio.contacts.R;
 | 
					import cc.winboll.studio.contacts.R;
 | 
				
			||||||
import cc.winboll.studio.libaes.winboll.APPInfo;
 | 
					import cc.winboll.studio.libaes.winboll.APPInfo;
 | 
				
			||||||
import cc.winboll.studio.libaes.winboll.AboutView;
 | 
					import cc.winboll.studio.libaes.winboll.AboutView;
 | 
				
			||||||
import cc.winboll.studio.libappbase.GlobalApplication;
 | 
					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";
 | 
					    public static final String TAG = "AboutActivity";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,13 +65,13 @@ public class AboutActivity extends WinBollActivity implements IWinBollActivity {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
        layout.addView(aboutView, params);
 | 
					        layout.addView(aboutView, params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        GlobalApplication.getWinBollActivityManager().add(this);
 | 
					        GlobalApplication.getWinBoLLActivityManager().add(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected void onDestroy() {
 | 
					    protected void onDestroy() {
 | 
				
			||||||
        super.onDestroy();
 | 
					        super.onDestroy();
 | 
				
			||||||
        GlobalApplication.getWinBollActivityManager().registeRemove(this);
 | 
					        GlobalApplication.getWinBoLLActivityManager().registeRemove(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public AboutView CreateAboutView() {
 | 
					    public AboutView CreateAboutView() {
 | 
				
			||||||
@@ -78,12 +79,12 @@ public class AboutActivity extends WinBollActivity implements IWinBollActivity {
 | 
				
			|||||||
        APPInfo appInfo = new APPInfo();
 | 
					        APPInfo appInfo = new APPInfo();
 | 
				
			||||||
        appInfo.setAppName("Contacts");
 | 
					        appInfo.setAppName("Contacts");
 | 
				
			||||||
        appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll);
 | 
					        appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll);
 | 
				
			||||||
        appInfo.setAppDescription("通讯录与拨号");
 | 
					        appInfo.setAppDescription("这是可以根据正则表达式匹配拦截骚扰电话的手机拨号应用。");
 | 
				
			||||||
        appInfo.setAppGitName("APP");
 | 
					        appInfo.setAppGitName("APPBase");
 | 
				
			||||||
        appInfo.setAppGitOwner("Studio");
 | 
					        appInfo.setAppGitOwner("Studio");
 | 
				
			||||||
        appInfo.setAppGitAPPBranch(szBranchName);
 | 
					        appInfo.setAppGitAPPBranch(szBranchName);
 | 
				
			||||||
        appInfo.setAppGitAPPSubProjectFolder(szBranchName);
 | 
					        appInfo.setAppGitAPPSubProjectFolder(szBranchName);
 | 
				
			||||||
        appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=Contacts");
 | 
					        appInfo.setAppHomePage("https://discuz.winboll.cc/forum.php?mod=viewthread&tid=4&extra=page%3D1");
 | 
				
			||||||
        appInfo.setAppAPKName("Contacts");
 | 
					        appInfo.setAppAPKName("Contacts");
 | 
				
			||||||
        appInfo.setAppAPKFolderName("Contacts");
 | 
					        appInfo.setAppAPKFolderName("Contacts");
 | 
				
			||||||
        return new AboutView(mContext, appInfo);
 | 
					        return new AboutView(mContext, appInfo);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.activities;
 | 
					package cc.winboll.studio.contacts.activities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/20 17:15:46
 | 
					 * @Date 2025/02/20 17:15:46
 | 
				
			||||||
 * @Describe 拨号窗口
 | 
					 * @Describe 拨号窗口
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.activities;
 | 
					package cc.winboll.studio.contacts.activities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/20 20:18:26
 | 
					 * @Date 2025/02/20 20:18:26
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.content.Intent;
 | 
					import android.content.Intent;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.activities;
 | 
					package cc.winboll.studio.contacts.activities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/21 05:37:42
 | 
					 * @Date 2025/02/21 05:37:42
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.content.Context;
 | 
					import android.content.Context;
 | 
				
			||||||
@@ -24,6 +24,7 @@ import androidx.appcompat.app.AppCompatActivity;
 | 
				
			|||||||
import androidx.appcompat.widget.Toolbar;
 | 
					import androidx.appcompat.widget.Toolbar;
 | 
				
			||||||
import androidx.recyclerview.widget.LinearLayoutManager;
 | 
					import androidx.recyclerview.widget.LinearLayoutManager;
 | 
				
			||||||
import androidx.recyclerview.widget.RecyclerView;
 | 
					import androidx.recyclerview.widget.RecyclerView;
 | 
				
			||||||
 | 
					import cc.winboll.studio.contacts.App;
 | 
				
			||||||
import cc.winboll.studio.contacts.R;
 | 
					import cc.winboll.studio.contacts.R;
 | 
				
			||||||
import cc.winboll.studio.contacts.adapters.PhoneConnectRuleAdapter;
 | 
					import cc.winboll.studio.contacts.adapters.PhoneConnectRuleAdapter;
 | 
				
			||||||
import cc.winboll.studio.contacts.beans.MainServiceBean;
 | 
					import cc.winboll.studio.contacts.beans.MainServiceBean;
 | 
				
			||||||
@@ -34,15 +35,13 @@ import cc.winboll.studio.contacts.bobulltoon.TomCat;
 | 
				
			|||||||
import cc.winboll.studio.contacts.dun.Rules;
 | 
					import cc.winboll.studio.contacts.dun.Rules;
 | 
				
			||||||
import cc.winboll.studio.contacts.services.MainService;
 | 
					import cc.winboll.studio.contacts.services.MainService;
 | 
				
			||||||
import cc.winboll.studio.contacts.views.DuInfoTextView;
 | 
					import cc.winboll.studio.contacts.views.DuInfoTextView;
 | 
				
			||||||
import cc.winboll.studio.libaes.winboll.APPInfo;
 | 
					 | 
				
			||||||
import cc.winboll.studio.libappbase.LogUtils;
 | 
					import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			||||||
import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
 | 
					import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
 | 
				
			||||||
import com.hjq.toast.ToastUtils;
 | 
					import com.hjq.toast.ToastUtils;
 | 
				
			||||||
import java.lang.reflect.Field;
 | 
					import java.lang.reflect.Field;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import cc.winboll.studio.contacts.App;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class SettingsActivity extends AppCompatActivity implements IWinBollActivity {
 | 
					public class SettingsActivity extends AppCompatActivity implements IWinBoLLActivity {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static final String TAG = "SettingsActivity";
 | 
					    public static final String TAG = "SettingsActivity";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -177,6 +176,8 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
 | 
				
			|||||||
        etDunResumeSecondCount.setEnabled(!isEnableDun);
 | 
					        etDunResumeSecondCount.setEnabled(!isEnableDun);
 | 
				
			||||||
        etDunResumeCount.setEnabled(!isEnableDun);
 | 
					        etDunResumeCount.setEnabled(!isEnableDun);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        EditText etBoBullToonURL = findViewById(R.id.bobulltoonurl_et);
 | 
				
			||||||
 | 
					        etBoBullToonURL.setText(Rules.getInstance(this).getBoBullToonURL());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void notifyDunInfoUpdate() {
 | 
					    public static void notifyDunInfoUpdate() {
 | 
				
			||||||
@@ -197,10 +198,19 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
 | 
				
			|||||||
            settingsModel.setDunTotalCount(Integer.parseInt(etDunTotalCount.getText().toString()));
 | 
					            settingsModel.setDunTotalCount(Integer.parseInt(etDunTotalCount.getText().toString()));
 | 
				
			||||||
            settingsModel.setDunResumeSecondCount(Integer.parseInt(etDunResumeSecondCount.getText().toString()));
 | 
					            settingsModel.setDunResumeSecondCount(Integer.parseInt(etDunResumeSecondCount.getText().toString()));
 | 
				
			||||||
            settingsModel.setDunResumeCount(Integer.parseInt(etDunResumeCount.getText().toString()));
 | 
					            settingsModel.setDunResumeCount(Integer.parseInt(etDunResumeCount.getText().toString()));
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// 应用效果提示
 | 
				
			||||||
 | 
								ToastUtils.show((settingsModel.getDunTotalCount() == 1)?"电话骚扰防御力几乎为0。":String.format("以下设置将在连拨%d次后接通电话。", settingsModel.getDunTotalCount()));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        settingsModel.setIsEnableDun(isEnableDun);
 | 
					        settingsModel.setIsEnableDun(isEnableDun);
 | 
				
			||||||
        Rules.getInstance(this).saveDun();
 | 
					        Rules.getInstance(this).saveDun();
 | 
				
			||||||
        Rules.getInstance(this).reload();
 | 
					        Rules.getInstance(this).reload();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // 重新加载盾牌参数
 | 
				
			||||||
 | 
					        etDunTotalCount.setText(Integer.toString(settingsModel.getDunTotalCount()));
 | 
				
			||||||
 | 
					        etDunResumeSecondCount.setText(Integer.toString(settingsModel.getDunResumeSecondCount()));
 | 
				
			||||||
 | 
					        etDunResumeCount.setText(Integer.toString(settingsModel.getDunResumeCount()));
 | 
				
			||||||
 | 
							
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void updateStreamVolumeTextView() {
 | 
					    void updateStreamVolumeTextView() {
 | 
				
			||||||
@@ -233,7 +243,21 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void onResetBoBullToonURL(View view) {
 | 
				
			||||||
 | 
					        Rules.getInstance(this).resetDefaultBoBullToonURL();
 | 
				
			||||||
 | 
					        EditText etBoBullToonURL = findViewById(R.id.bobulltoonurl_et);
 | 
				
			||||||
 | 
					        etBoBullToonURL.setText(Rules.getInstance(this).getBoBullToonURL());
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							final TomCat tomCat = TomCat.getInstance(this);
 | 
				
			||||||
 | 
							tomCat.cleanBoBullToon();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void onDownloadBoBullToon(View view) {
 | 
					    public void onDownloadBoBullToon(View view) {
 | 
				
			||||||
 | 
					        EditText etBoBullToonURL = findViewById(R.id.bobulltoonurl_et);
 | 
				
			||||||
 | 
					        if (!etBoBullToonURL.getText().toString().trim().equals(Rules.getInstance(this).getBoBullToonURL())) {
 | 
				
			||||||
 | 
					            Rules.getInstance(this).setBoBullToonURL(etBoBullToonURL.getText().toString().trim());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        final TomCat tomCat = TomCat.getInstance(this);
 | 
					        final TomCat tomCat = TomCat.getInstance(this);
 | 
				
			||||||
        new Thread(new Runnable() {
 | 
					        new Thread(new Runnable() {
 | 
				
			||||||
                @Override
 | 
					                @Override
 | 
				
			||||||
@@ -247,8 +271,6 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
 | 
				
			|||||||
            }).start();
 | 
					            }).start();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void onSearchBoBullToonPhone(View view) {
 | 
					    public void onSearchBoBullToonPhone(View view) {
 | 
				
			||||||
        TomCat tomCat = TomCat.getInstance(this);
 | 
					        TomCat tomCat = TomCat.getInstance(this);
 | 
				
			||||||
        EditText etPhone = findViewById(R.id.activitysettingsEditText1);
 | 
					        EditText etPhone = findViewById(R.id.activitysettingsEditText1);
 | 
				
			||||||
@@ -311,8 +333,12 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    public void onAbout(View view) {
 | 
					    public void onAbout(View view) {
 | 
				
			||||||
        App.getWinBollActivityManager().startWinBollActivity(this, AboutActivity.class);
 | 
					        App.getWinBoLLActivityManager().startWinBoLLActivity(this, AboutActivity.class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						public void onLogView(View view) {
 | 
				
			||||||
 | 
					        App.getWinBoLLActivityManager().startLogActivity(this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			|||||||
import cc.winboll.studio.libappbase.LogView;
 | 
					import cc.winboll.studio.libappbase.LogView;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/02 16:07:04
 | 
					 * @Date 2025/03/02 16:07:04
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class UnitTestActivity extends Activity {
 | 
					public class UnitTestActivity extends Activity {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.activities;
 | 
					package cc.winboll.studio.contacts.activities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/31 15:16:45
 | 
					 * @Date 2025/03/31 15:16:45
 | 
				
			||||||
 * @Describe 应用窗口基类
 | 
					 * @Describe 应用窗口基类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -11,9 +11,9 @@ import android.view.MenuItem;
 | 
				
			|||||||
import androidx.appcompat.app.AppCompatActivity;
 | 
					import androidx.appcompat.app.AppCompatActivity;
 | 
				
			||||||
import cc.winboll.studio.libaes.beans.AESThemeBean;
 | 
					import cc.winboll.studio.libaes.beans.AESThemeBean;
 | 
				
			||||||
import cc.winboll.studio.libaes.utils.AESThemeUtil;
 | 
					import cc.winboll.studio.libaes.utils.AESThemeUtil;
 | 
				
			||||||
import cc.winboll.studio.libappbase.winboll.IWinBollActivity;
 | 
					import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class WinBollActivity extends AppCompatActivity implements IWinBollActivity {
 | 
					public class WinBollActivity extends AppCompatActivity implements IWinBoLLActivity {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static final String TAG = "WinBollActivity";
 | 
					    public static final String TAG = "WinBollActivity";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,22 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.adapters;
 | 
					package cc.winboll.studio.contacts.adapters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/26 13:09:32
 | 
					 * @Date 2025/02/26 13:09:32
 | 
				
			||||||
 * @Describe CallLogAdapter
 | 
					 * @Describe CallLogAdapter
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					import android.content.ClipData;
 | 
				
			||||||
 | 
					import android.content.ClipboardManager;
 | 
				
			||||||
import android.content.Context;
 | 
					import android.content.Context;
 | 
				
			||||||
import android.content.Intent;
 | 
					import android.content.Intent;
 | 
				
			||||||
import android.view.LayoutInflater;
 | 
					import android.view.LayoutInflater;
 | 
				
			||||||
 | 
					import android.view.MenuItem;
 | 
				
			||||||
import android.view.View;
 | 
					import android.view.View;
 | 
				
			||||||
import android.view.ViewGroup;
 | 
					import android.view.ViewGroup;
 | 
				
			||||||
import android.widget.Button;
 | 
					import android.widget.Button;
 | 
				
			||||||
 | 
					import android.widget.PopupMenu;
 | 
				
			||||||
import android.widget.TextView;
 | 
					import android.widget.TextView;
 | 
				
			||||||
 | 
					import android.widget.Toast;
 | 
				
			||||||
import androidx.annotation.NonNull;
 | 
					import androidx.annotation.NonNull;
 | 
				
			||||||
import androidx.recyclerview.widget.RecyclerView;
 | 
					import androidx.recyclerview.widget.RecyclerView;
 | 
				
			||||||
import cc.winboll.studio.contacts.R;
 | 
					import cc.winboll.studio.contacts.R;
 | 
				
			||||||
@@ -35,6 +40,10 @@ public class CallLogAdapter extends RecyclerView.Adapter<CallLogAdapter.CallLogV
 | 
				
			|||||||
        this.mContactUtils = ContactUtils.getInstance(mContext);
 | 
					        this.mContactUtils = ContactUtils.getInstance(mContext);
 | 
				
			||||||
        this.callLogList = callLogList;
 | 
					        this.callLogList = callLogList;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						public void relaodContacts() {
 | 
				
			||||||
 | 
							this.mContactUtils.relaodContacts();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @NonNull
 | 
					    @NonNull
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@@ -47,6 +56,38 @@ public class CallLogAdapter extends RecyclerView.Adapter<CallLogAdapter.CallLogV
 | 
				
			|||||||
    public void onBindViewHolder(@NonNull CallLogViewHolder holder, int position) {
 | 
					    public void onBindViewHolder(@NonNull CallLogViewHolder holder, int position) {
 | 
				
			||||||
        final CallLogModel callLog = callLogList.get(position);
 | 
					        final CallLogModel callLog = callLogList.get(position);
 | 
				
			||||||
        holder.phoneNumber.setText(callLog.getPhoneNumber() + "☎" + mContactUtils.getContactsName(callLog.getPhoneNumber()));
 | 
					        holder.phoneNumber.setText(callLog.getPhoneNumber() + "☎" + mContactUtils.getContactsName(callLog.getPhoneNumber()));
 | 
				
			||||||
 | 
							holder.phoneNumber.setOnLongClickListener(new View.OnLongClickListener() {
 | 
				
			||||||
 | 
									@Override
 | 
				
			||||||
 | 
									public boolean onLongClick(View p1) {
 | 
				
			||||||
 | 
										// 弹出复制菜单
 | 
				
			||||||
 | 
										PopupMenu menu = new PopupMenu(mContext, holder.phoneNumber);
 | 
				
			||||||
 | 
										//加载菜单资源
 | 
				
			||||||
 | 
										menu.getMenuInflater().inflate(R.menu.toolbar_calllog_phonenumber, menu.getMenu());
 | 
				
			||||||
 | 
										//设置点击事件的响应
 | 
				
			||||||
 | 
										menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
 | 
				
			||||||
 | 
												@Override
 | 
				
			||||||
 | 
												public boolean onMenuItemClick(MenuItem menuItem) {
 | 
				
			||||||
 | 
													int nItemId = menuItem.getItemId();
 | 
				
			||||||
 | 
													if (nItemId == R.id.item_calllog_phonenumber_copy) {
 | 
				
			||||||
 | 
														// Gets a handle to the clipboard service.
 | 
				
			||||||
 | 
														ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
 | 
				
			||||||
 | 
														// Creates a new text clip to put on the clipboard
 | 
				
			||||||
 | 
														ClipData clip = ClipData.newPlainText("simple text", callLog.getPhoneNumber());
 | 
				
			||||||
 | 
														// Set the clipboard's primary clip.
 | 
				
			||||||
 | 
														clipboard.setPrimaryClip(clip);
 | 
				
			||||||
 | 
														Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show();
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
													return true;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											});
 | 
				
			||||||
 | 
										//一定要调用show()来显示弹出式菜单
 | 
				
			||||||
 | 
										menu.show();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							
 | 
				
			||||||
        holder.callStatus.setText(callLog.getCallStatus());
 | 
					        holder.callStatus.setText(callLog.getCallStatus());
 | 
				
			||||||
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
 | 
					        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
 | 
				
			||||||
        holder.callDate.setText(dateFormat.format(callLog.getCallDate()));
 | 
					        holder.callDate.setText(dateFormat.format(callLog.getCallDate()));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,29 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.adapters;
 | 
					package cc.winboll.studio.contacts.adapters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/26 13:35:44
 | 
					 * @Date 2025/02/26 13:35:44
 | 
				
			||||||
 * @Describe ContactAdapter
 | 
					 * @Describe ContactAdapter
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					import android.content.ClipData;
 | 
				
			||||||
 | 
					import android.content.ClipboardManager;
 | 
				
			||||||
 | 
					import android.content.Context;
 | 
				
			||||||
import android.content.Intent;
 | 
					import android.content.Intent;
 | 
				
			||||||
import android.view.LayoutInflater;
 | 
					import android.view.LayoutInflater;
 | 
				
			||||||
 | 
					import android.view.MenuItem;
 | 
				
			||||||
import android.view.View;
 | 
					import android.view.View;
 | 
				
			||||||
import android.view.ViewGroup;
 | 
					import android.view.ViewGroup;
 | 
				
			||||||
import android.widget.Button;
 | 
					import android.widget.LinearLayout;
 | 
				
			||||||
 | 
					import android.widget.PopupMenu;
 | 
				
			||||||
import android.widget.TextView;
 | 
					import android.widget.TextView;
 | 
				
			||||||
 | 
					import android.widget.Toast;
 | 
				
			||||||
import androidx.annotation.NonNull;
 | 
					import androidx.annotation.NonNull;
 | 
				
			||||||
import androidx.recyclerview.widget.RecyclerView;
 | 
					import androidx.recyclerview.widget.RecyclerView;
 | 
				
			||||||
import cc.winboll.studio.contacts.R;
 | 
					import cc.winboll.studio.contacts.R;
 | 
				
			||||||
import cc.winboll.studio.contacts.beans.ContactModel;
 | 
					import cc.winboll.studio.contacts.beans.ContactModel;
 | 
				
			||||||
 | 
					import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
 | 
				
			||||||
import com.hjq.toast.ToastUtils;
 | 
					import com.hjq.toast.ToastUtils;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {
 | 
					public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,8 +32,10 @@ public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactV
 | 
				
			|||||||
    private static final int REQUEST_CALL_PHONE = 1;
 | 
					    private static final int REQUEST_CALL_PHONE = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private List<ContactModel> contactList;
 | 
					    private List<ContactModel> contactList;
 | 
				
			||||||
 | 
						Context mContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ContactAdapter(List<ContactModel> contactList) {
 | 
					    public ContactAdapter(Context context, List<ContactModel> contactList) {
 | 
				
			||||||
 | 
							mContext = context;
 | 
				
			||||||
        this.contactList = contactList;
 | 
					        this.contactList = contactList;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -41,6 +49,37 @@ public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactV
 | 
				
			|||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onBindViewHolder(@NonNull ContactViewHolder holder, int position) {
 | 
					    public void onBindViewHolder(@NonNull ContactViewHolder holder, int position) {
 | 
				
			||||||
        final ContactModel contact = contactList.get(position);
 | 
					        final ContactModel contact = contactList.get(position);
 | 
				
			||||||
 | 
							holder.llPhoneNumberMain.setOnLongClickListener(new View.OnLongClickListener() {
 | 
				
			||||||
 | 
									@Override
 | 
				
			||||||
 | 
									public boolean onLongClick(View p1) {
 | 
				
			||||||
 | 
										// 弹出复制菜单
 | 
				
			||||||
 | 
										PopupMenu menu = new PopupMenu(mContext, holder.llPhoneNumberMain);
 | 
				
			||||||
 | 
										//加载菜单资源
 | 
				
			||||||
 | 
										menu.getMenuInflater().inflate(R.menu.toolbar_contact_phonenumber, menu.getMenu());
 | 
				
			||||||
 | 
										//设置点击事件的响应
 | 
				
			||||||
 | 
										menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
 | 
				
			||||||
 | 
												@Override
 | 
				
			||||||
 | 
												public boolean onMenuItemClick(MenuItem menuItem) {
 | 
				
			||||||
 | 
													int nItemId = menuItem.getItemId();
 | 
				
			||||||
 | 
													if (nItemId == R.id.item_contact_phonenumber_copy) {
 | 
				
			||||||
 | 
														// Gets a handle to the clipboard service.
 | 
				
			||||||
 | 
														ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
 | 
				
			||||||
 | 
														// Creates a new text clip to put on the clipboard
 | 
				
			||||||
 | 
														ClipData clip = ClipData.newPlainText("simple text", contact.getNumber());
 | 
				
			||||||
 | 
														// Set the clipboard's primary clip.
 | 
				
			||||||
 | 
														clipboard.setPrimaryClip(clip);
 | 
				
			||||||
 | 
														Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show();
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
													return true;
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
											});
 | 
				
			||||||
 | 
										//一定要调用show()来显示弹出式菜单
 | 
				
			||||||
 | 
										menu.show();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
        holder.contactName.setText(contact.getName());
 | 
					        holder.contactName.setText(contact.getName());
 | 
				
			||||||
        holder.contactNumber.setText(contact.getNumber());
 | 
					        holder.contactNumber.setText(contact.getNumber());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,12 +108,14 @@ public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactV
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public class ContactViewHolder extends RecyclerView.ViewHolder {
 | 
					    public class ContactViewHolder extends RecyclerView.ViewHolder {
 | 
				
			||||||
 | 
							LinearLayout llPhoneNumberMain;
 | 
				
			||||||
        TextView contactName;
 | 
					        TextView contactName;
 | 
				
			||||||
        TextView contactNumber;
 | 
					        TextView contactNumber;
 | 
				
			||||||
        AOHPCTCSeekBar dialAOHPCTCSeekBar;
 | 
					        AOHPCTCSeekBar dialAOHPCTCSeekBar;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        public ContactViewHolder(@NonNull View itemView) {
 | 
					        public ContactViewHolder(@NonNull View itemView) {
 | 
				
			||||||
            super(itemView);
 | 
					            super(itemView);
 | 
				
			||||||
 | 
								llPhoneNumberMain = itemView.findViewById(R.id.itemcontactLinearLayout1);
 | 
				
			||||||
            contactName = itemView.findViewById(R.id.contact_name);
 | 
					            contactName = itemView.findViewById(R.id.contact_name);
 | 
				
			||||||
            contactNumber = itemView.findViewById(R.id.contact_number);
 | 
					            contactNumber = itemView.findViewById(R.id.contact_number);
 | 
				
			||||||
            dialAOHPCTCSeekBar = itemView.findViewById(R.id.aohpctcseekbar_dial);
 | 
					            dialAOHPCTCSeekBar = itemView.findViewById(R.id.aohpctcseekbar_dial);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.adapters;
 | 
					package cc.winboll.studio.contacts.adapters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/20 14:20:38
 | 
					 * @Date 2025/02/20 14:20:38
 | 
				
			||||||
 * @Describe ImagePagerAdapter
 | 
					 * @Describe ImagePagerAdapter
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,13 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.adapters;
 | 
					package cc.winboll.studio.contacts.adapters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/02 17:27:41
 | 
					 * @Date 2025/03/02 17:27:41
 | 
				
			||||||
 * @Describe PhoneConnectRuleAdapter
 | 
					 * @Describe PhoneConnectRuleAdapter
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.content.Context;
 | 
					import android.content.Context;
 | 
				
			||||||
import android.view.LayoutInflater;
 | 
					import android.view.LayoutInflater;
 | 
				
			||||||
 | 
					import android.view.MotionEvent;
 | 
				
			||||||
import android.view.View;
 | 
					import android.view.View;
 | 
				
			||||||
import android.view.ViewGroup;
 | 
					import android.view.ViewGroup;
 | 
				
			||||||
import android.widget.Button;
 | 
					import android.widget.Button;
 | 
				
			||||||
@@ -20,6 +21,7 @@ import cc.winboll.studio.contacts.R;
 | 
				
			|||||||
import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel;
 | 
					import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel;
 | 
				
			||||||
import cc.winboll.studio.contacts.dun.Rules;
 | 
					import cc.winboll.studio.contacts.dun.Rules;
 | 
				
			||||||
import cc.winboll.studio.contacts.views.LeftScrollView;
 | 
					import cc.winboll.studio.contacts.views.LeftScrollView;
 | 
				
			||||||
 | 
					import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			||||||
import cc.winboll.studio.libappbase.dialogs.YesNoAlertDialog;
 | 
					import cc.winboll.studio.libappbase.dialogs.YesNoAlertDialog;
 | 
				
			||||||
import com.hjq.toast.ToastUtils;
 | 
					import com.hjq.toast.ToastUtils;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
@@ -60,6 +62,10 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
 | 
				
			|||||||
            final SimpleViewHolder simpleViewHolder = (SimpleViewHolder) holder;
 | 
					            final SimpleViewHolder simpleViewHolder = (SimpleViewHolder) holder;
 | 
				
			||||||
            String szView = model.getRuleText().trim().equals("") ?"[NULL]": model.getRuleText();
 | 
					            String szView = model.getRuleText().trim().equals("") ?"[NULL]": model.getRuleText();
 | 
				
			||||||
            simpleViewHolder.tvRuleText.setText(szView);
 | 
					            simpleViewHolder.tvRuleText.setText(szView);
 | 
				
			||||||
 | 
					            simpleViewHolder.checkBoxAllow.setChecked(model.isAllowConnection());
 | 
				
			||||||
 | 
								simpleViewHolder.checkBoxAllow.setEnabled(false);
 | 
				
			||||||
 | 
					            simpleViewHolder.checkBoxEnable.setChecked(model.isEnable());
 | 
				
			||||||
 | 
								simpleViewHolder.checkBoxEnable.setEnabled(false);
 | 
				
			||||||
            simpleViewHolder.scrollView.setOnActionListener(new LeftScrollView.OnActionListener(){
 | 
					            simpleViewHolder.scrollView.setOnActionListener(new LeftScrollView.OnActionListener(){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    @Override
 | 
					                    @Override
 | 
				
			||||||
@@ -215,16 +221,22 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private final LeftScrollView scrollView;
 | 
					        private final LeftScrollView scrollView;
 | 
				
			||||||
        private final TextView tvRuleText;
 | 
					        private final TextView tvRuleText;
 | 
				
			||||||
 | 
							CheckBox checkBoxAllow;
 | 
				
			||||||
 | 
					        CheckBox checkBoxEnable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public SimpleViewHolder(@NonNull ViewGroup parent, @NonNull View itemView) {
 | 
					        public SimpleViewHolder(@NonNull ViewGroup parent, @NonNull View itemView) {
 | 
				
			||||||
            super(itemView);
 | 
					            super(itemView);
 | 
				
			||||||
            scrollView = itemView.findViewById(R.id.scrollView);
 | 
					            scrollView = itemView.findViewById(R.id.scrollView);
 | 
				
			||||||
            //tvRuleText = itemView.findViewById(R.id.ruletext_tv);
 | 
								LayoutInflater inflater = LayoutInflater.from(itemView.getContext());
 | 
				
			||||||
            tvRuleText = new TextView(itemView.getContext());
 | 
							    View viewContent = inflater.inflate(R.layout.view_phone_connect_rule_simple_content, parent, false);
 | 
				
			||||||
 | 
					            tvRuleText = viewContent.findViewById(R.id.ruletext_tv);
 | 
				
			||||||
 | 
					            checkBoxAllow = viewContent.findViewById(R.id.checkbox_allow);
 | 
				
			||||||
 | 
					            checkBoxEnable = viewContent.findViewById(R.id.checkbox_enable);
 | 
				
			||||||
 | 
					            //tvRuleText = new TextView(itemView.getContext());
 | 
				
			||||||
            scrollView.setContentWidth(parent.getWidth());
 | 
					            scrollView.setContentWidth(parent.getWidth());
 | 
				
			||||||
            //scrollView.setContentWidth(600);
 | 
					            //scrollView.setContentWidth(600);
 | 
				
			||||||
            scrollView.addContentLayout(tvRuleText);
 | 
					            scrollView.addContentLayout(viewContent);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -243,5 +255,9 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
 | 
				
			|||||||
            buttonConfirm = itemView.findViewById(R.id.button_confirm);
 | 
					            buttonConfirm = itemView.findViewById(R.id.button_confirm);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void setCheckBoxTouchListener(CheckBox checkBox) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.beans;
 | 
					package cc.winboll.studio.contacts.beans;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/26 13:10:57
 | 
					 * @Date 2025/02/26 13:10:57
 | 
				
			||||||
 * @Describe CallLogModel
 | 
					 * @Describe CallLogModel
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.beans;
 | 
					package cc.winboll.studio.contacts.beans;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/26 13:37:00
 | 
					 * @Date 2025/08/30 14:32
 | 
				
			||||||
 * @Describe ContactModel
 | 
					 * @Describe 联系人信息数据模型
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import net.sourceforge.pinyin4j.PinyinHelper;
 | 
					import net.sourceforge.pinyin4j.PinyinHelper;
 | 
				
			||||||
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
 | 
					import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
 | 
				
			||||||
@@ -18,13 +18,18 @@ public class ContactModel {
 | 
				
			|||||||
    private String name;
 | 
					    private String name;
 | 
				
			||||||
    private String number;
 | 
					    private String number;
 | 
				
			||||||
    private String pinyin;
 | 
					    private String pinyin;
 | 
				
			||||||
 | 
					    // 新增:存储姓名的拼音首字母(如"啊牛"→"an")
 | 
				
			||||||
 | 
					    private String pinyinFirstLetter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ContactModel(String name, String number) {
 | 
					    public ContactModel(String name, String number) {
 | 
				
			||||||
        this.name = name;
 | 
					        this.name = name;
 | 
				
			||||||
        this.number = number.replaceAll("\\s", "");
 | 
					        this.number = number.replaceAll("\\s", "");
 | 
				
			||||||
        this.pinyin = convertToPinyin(name);
 | 
					        this.pinyin = convertToPinyin(name);
 | 
				
			||||||
 | 
					        // 初始化时生成拼音首字母
 | 
				
			||||||
 | 
					        this.pinyinFirstLetter = convertToPinyinFirstLetter(name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 原方法:转换为全拼(如"啊牛"→"aniu")
 | 
				
			||||||
    private String convertToPinyin(String chinese) {
 | 
					    private String convertToPinyin(String chinese) {
 | 
				
			||||||
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
 | 
					        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
 | 
				
			||||||
        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
 | 
					        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
 | 
				
			||||||
@@ -33,22 +38,55 @@ public class ContactModel {
 | 
				
			|||||||
        StringBuilder pinyin = new StringBuilder();
 | 
					        StringBuilder pinyin = new StringBuilder();
 | 
				
			||||||
        for (int i = 0; i < chinese.length(); i++) {
 | 
					        for (int i = 0; i < chinese.length(); i++) {
 | 
				
			||||||
            char ch = chinese.charAt(i);
 | 
					            char ch = chinese.charAt(i);
 | 
				
			||||||
            if (Character.toString(ch).matches("[\\u4e00-\\u9fa5]")) {
 | 
					            if (Character.toString(ch).matches("[\\u4e00-\\u9fa5]")) { // 仅处理汉字
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, format);
 | 
					                    String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, format);
 | 
				
			||||||
                    if (pinyinArray != null) {
 | 
					                    if (pinyinArray != null && pinyinArray.length > 0) {
 | 
				
			||||||
                        pinyin.append(pinyinArray[0]);
 | 
					                        pinyin.append(pinyinArray[0]); // 取第一个拼音(多音字默认首选项)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } catch (BadHanyuPinyinOutputFormatCombination e) {
 | 
					                } catch (BadHanyuPinyinOutputFormatCombination e) {
 | 
				
			||||||
                    e.printStackTrace();
 | 
					                    e.printStackTrace();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                pinyin.append(ch);
 | 
					                pinyin.append(ch); // 非汉字直接拼接(如字母、数字、符号)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return pinyin.toString();
 | 
					        return pinyin.toString();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 新增:转换为拼音首字母(如"啊牛"→"an")
 | 
				
			||||||
 | 
					    private String convertToPinyinFirstLetter(String chinese) {
 | 
				
			||||||
 | 
					        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
 | 
				
			||||||
 | 
					        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
 | 
				
			||||||
 | 
					        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        StringBuilder firstLetters = new StringBuilder();
 | 
				
			||||||
 | 
					        for (int i = 0; i < chinese.length(); i++) {
 | 
				
			||||||
 | 
					            char ch = chinese.charAt(i);
 | 
				
			||||||
 | 
					            if (Character.toString(ch).matches("[\\u4e00-\\u9fa5]")) { // 仅处理汉字
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, format);
 | 
				
			||||||
 | 
					                    if (pinyinArray != null && pinyinArray.length > 0) {
 | 
				
			||||||
 | 
					                        // 取拼音的第一个字母(如"a"、"niu"→"a"、"n")
 | 
				
			||||||
 | 
					                        firstLetters.append(pinyinArray[0].charAt(0));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } catch (BadHanyuPinyinOutputFormatCombination e) {
 | 
				
			||||||
 | 
					                    e.printStackTrace();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // 非汉字可根据需求处理:此处保留原字符(如"李3"→"l3","张A"→"za")
 | 
				
			||||||
 | 
					                firstLetters.append(ch);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return firstLetters.toString();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 新增:获取拼音首字母
 | 
				
			||||||
 | 
					    public String getPinyinFirstLetter() {
 | 
				
			||||||
 | 
					        return pinyinFirstLetter;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 原有getter方法
 | 
				
			||||||
    public String getName() {
 | 
					    public String getName() {
 | 
				
			||||||
        return name;
 | 
					        return name;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.beans;
 | 
					package cc.winboll.studio.contacts.beans;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/13 07:06:13
 | 
					 * @Date 2025/02/13 07:06:13
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.util.JsonReader;
 | 
					import android.util.JsonReader;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.beans;
 | 
					package cc.winboll.studio.contacts.beans;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/21 09:52:10
 | 
					 * @Date 2025/02/21 09:52:10
 | 
				
			||||||
 * @Describe 电话黑名单规则
 | 
					 * @Describe 电话黑名单规则
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.beans;
 | 
					package cc.winboll.studio.contacts.beans;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/24 18:47:11
 | 
					 * @Date 2025/02/24 18:47:11
 | 
				
			||||||
 * @Describe 手机铃声设置参数类
 | 
					 * @Describe 手机铃声设置参数类
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.beans;
 | 
					package cc.winboll.studio.contacts.beans;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/02 19:51:40
 | 
					 * @Date 2025/03/02 19:51:40
 | 
				
			||||||
 * @Describe SettingsModel
 | 
					 * @Describe SettingsModel
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -14,6 +14,7 @@ import cc.winboll.studio.contacts.utils.IntUtils;
 | 
				
			|||||||
public class SettingsModel extends BaseBean {
 | 
					public class SettingsModel extends BaseBean {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static final String TAG = "SettingsModel";
 | 
					    public static final String TAG = "SettingsModel";
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    public static final int MAX_INTRANGE = 666666;
 | 
					    public static final int MAX_INTRANGE = 666666;
 | 
				
			||||||
    public static final int MIN_INTRANGE = 1;
 | 
					    public static final int MIN_INTRANGE = 1;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
@@ -27,6 +28,8 @@ public class SettingsModel extends BaseBean {
 | 
				
			|||||||
    int dunResumeCount;
 | 
					    int dunResumeCount;
 | 
				
			||||||
    // 是否启用云盾
 | 
					    // 是否启用云盾
 | 
				
			||||||
    boolean isEnableDun;
 | 
					    boolean isEnableDun;
 | 
				
			||||||
 | 
					    // BoBullToon 应用模块数据请求地址
 | 
				
			||||||
 | 
					    String szBoBullToon_URL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public SettingsModel() {
 | 
					    public SettingsModel() {
 | 
				
			||||||
        this.dunTotalCount = 6;
 | 
					        this.dunTotalCount = 6;
 | 
				
			||||||
@@ -34,14 +37,24 @@ public class SettingsModel extends BaseBean {
 | 
				
			|||||||
        this.dunResumeSecondCount = 60;
 | 
					        this.dunResumeSecondCount = 60;
 | 
				
			||||||
        this.dunResumeCount = 1;
 | 
					        this.dunResumeCount = 1;
 | 
				
			||||||
        this.isEnableDun = false;
 | 
					        this.isEnableDun = false;
 | 
				
			||||||
 | 
					        this.szBoBullToon_URL = "";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public SettingsModel(int dunTotalCount, int dunCurrentCount, int dunResumeSecondCount, int dunResumeCount, boolean isEnableDun) {
 | 
					    public SettingsModel(int dunTotalCount, int dunCurrentCount, int dunResumeSecondCount, int dunResumeCount, boolean isEnableDun, String szBoBullToon_URL) {
 | 
				
			||||||
        this.dunTotalCount = getSettingsModelRangeInt(dunTotalCount);
 | 
					        this.dunTotalCount = getSettingsModelRangeInt(dunTotalCount);
 | 
				
			||||||
        this.dunCurrentCount = getSettingsModelRangeInt(dunCurrentCount);
 | 
					        this.dunCurrentCount = getSettingsModelRangeInt(dunCurrentCount);
 | 
				
			||||||
        this.dunResumeSecondCount = getSettingsModelRangeInt(dunResumeSecondCount);
 | 
					        this.dunResumeSecondCount = getSettingsModelRangeInt(dunResumeSecondCount);
 | 
				
			||||||
        this.dunResumeCount = getSettingsModelRangeInt(dunResumeCount);
 | 
					        this.dunResumeCount = getSettingsModelRangeInt(dunResumeCount);
 | 
				
			||||||
        this.isEnableDun = isEnableDun;
 | 
					        this.isEnableDun = isEnableDun;
 | 
				
			||||||
 | 
					        this.szBoBullToon_URL = szBoBullToon_URL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setBoBullToon_URL(String boBullToon_URL) {
 | 
				
			||||||
 | 
					        this.szBoBullToon_URL = boBullToon_URL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getBoBullToon_URL() {
 | 
				
			||||||
 | 
					        return szBoBullToon_URL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setDunTotalCount(int dunTotalCount) {
 | 
					    public void setDunTotalCount(int dunTotalCount) {
 | 
				
			||||||
@@ -102,7 +115,8 @@ public class SettingsModel extends BaseBean {
 | 
				
			|||||||
        jsonWriter.name("dunResumeSecondCount").value(getDunResumeSecondCount());
 | 
					        jsonWriter.name("dunResumeSecondCount").value(getDunResumeSecondCount());
 | 
				
			||||||
        jsonWriter.name("dunResumeCount").value(getDunResumeCount());
 | 
					        jsonWriter.name("dunResumeCount").value(getDunResumeCount());
 | 
				
			||||||
        jsonWriter.name("isEnableDun").value(isEnableDun());
 | 
					        jsonWriter.name("isEnableDun").value(isEnableDun());
 | 
				
			||||||
 | 
					        jsonWriter.name("szBoBullToon_URL").value(getBoBullToon_URL());
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@@ -118,6 +132,8 @@ public class SettingsModel extends BaseBean {
 | 
				
			|||||||
                setDunResumeCount(getSettingsModelRangeInt(jsonReader.nextInt()));
 | 
					                setDunResumeCount(getSettingsModelRangeInt(jsonReader.nextInt()));
 | 
				
			||||||
            } else if (name.equals("isEnableDun")) {
 | 
					            } else if (name.equals("isEnableDun")) {
 | 
				
			||||||
                setIsEnableDun(jsonReader.nextBoolean());
 | 
					                setIsEnableDun(jsonReader.nextBoolean());
 | 
				
			||||||
 | 
					            } else if (name.equals("szBoBullToon_URL")) {
 | 
				
			||||||
 | 
					                setBoBullToon_URL(jsonReader.nextString());
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,17 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.bobulltoon;
 | 
					package cc.winboll.studio.contacts.bobulltoon;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/02 13:47:48
 | 
					 * @Date 2025/03/02 13:47:48
 | 
				
			||||||
 * @Describe 汤姆猫管家 :使用 BoBullToon 项目,对通讯地址进行筛选判断的好朋友。
 | 
					 * @Describe 汤姆猫管家 :使用 BoBullToon 项目,对通讯地址进行筛选判断的好朋友。
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.content.Context;
 | 
					import android.content.Context;
 | 
				
			||||||
 | 
					import cc.winboll.studio.contacts.R;
 | 
				
			||||||
 | 
					import cc.winboll.studio.contacts.dun.Rules;
 | 
				
			||||||
import cc.winboll.studio.libappbase.LogUtils;
 | 
					import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			||||||
import com.hjq.toast.ToastUtils;
 | 
					import com.hjq.toast.ToastUtils;
 | 
				
			||||||
import java.io.File;
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.io.FileFilter;
 | 
				
			||||||
import java.io.FileOutputStream;
 | 
					import java.io.FileOutputStream;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.io.InputStream;
 | 
					import java.io.InputStream;
 | 
				
			||||||
@@ -28,6 +31,7 @@ public class TomCat {
 | 
				
			|||||||
    public static final String TAG = "TomCat";
 | 
					    public static final String TAG = "TomCat";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    List<String> listPhoneBoBullToon = new ArrayList<String>();
 | 
					    List<String> listPhoneBoBullToon = new ArrayList<String>();
 | 
				
			||||||
 | 
					    String mszBoBullToon_URL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static volatile TomCat _TomCat;
 | 
					    static volatile TomCat _TomCat;
 | 
				
			||||||
    Context mContext;
 | 
					    Context mContext;
 | 
				
			||||||
@@ -42,7 +46,11 @@ public class TomCat {
 | 
				
			|||||||
        return _TomCat;
 | 
					        return _TomCat;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void downloadAndExtractZip(String zipUrl, String destinationFolder) throws IOException {
 | 
					    public String getDefaultBobulltoonUrl() {
 | 
				
			||||||
 | 
					        return mContext.getString(R.string.default_bobulltoon_url);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    boolean downloadAndExtractZip(String zipUrl, String destinationFolder) throws IOException {
 | 
				
			||||||
        OkHttpClient client = new OkHttpClient();
 | 
					        OkHttpClient client = new OkHttpClient();
 | 
				
			||||||
        Request request = new Request.Builder()
 | 
					        Request request = new Request.Builder()
 | 
				
			||||||
            .url(zipUrl)
 | 
					            .url(zipUrl)
 | 
				
			||||||
@@ -95,13 +103,16 @@ public class TomCat {
 | 
				
			|||||||
            // 删除临时 ZIP 文件
 | 
					            // 删除临时 ZIP 文件
 | 
				
			||||||
            tempZipFile.delete();
 | 
					            tempZipFile.delete();
 | 
				
			||||||
            LogUtils.d(TAG, "已更新 BoBullToon 数据");
 | 
					            LogUtils.d(TAG, "已更新 BoBullToon 数据");
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
        } catch (Exception e) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
					            ToastUtils.show(e.getMessage());
 | 
				
			||||||
            LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
 | 
					            LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean downloadBoBullToon() {
 | 
					    public boolean downloadBoBullToon() {
 | 
				
			||||||
        String zipUrl = "http://10.8.0.12:3000/Studio/BoBullToon/archive/main.zip"; // 替换为实际的 ZIP 文件 URL
 | 
					        String zipUrl = Rules.getInstance(mContext).getBoBullToonURL(); // 替换为实际的 ZIP 文件 URL
 | 
				
			||||||
        String destinationFolder = getWorkingFolder().getPath(); // 替换为实际的目标文件夹路径
 | 
					        String destinationFolder = getWorkingFolder().getPath(); // 替换为实际的目标文件夹路径
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            // 删除旧文件
 | 
					            // 删除旧文件
 | 
				
			||||||
@@ -113,9 +124,11 @@ public class TomCat {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 更新新文件
 | 
					            // 更新新文件
 | 
				
			||||||
            downloadAndExtractZip(zipUrl, destinationFolder);
 | 
					            if (downloadAndExtractZip(zipUrl, destinationFolder)) {
 | 
				
			||||||
            LogUtils.d(TAG, "ZIP 文件下载并解压成功。");
 | 
					                LogUtils.d(TAG, "ZIP 文件下载并解压成功。");
 | 
				
			||||||
            return true;
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
        } catch (IOException e) {
 | 
					        } catch (IOException e) {
 | 
				
			||||||
            LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
 | 
					            LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -142,12 +155,81 @@ public class TomCat {
 | 
				
			|||||||
    File getWorkingFolder() {
 | 
					    File getWorkingFolder() {
 | 
				
			||||||
        return mContext.getExternalFilesDir(TAG);
 | 
					        return mContext.getExternalFilesDir(TAG);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						public File getBoBullToonDataFolder() {
 | 
				
			||||||
 | 
							File fCheckRoot = getWorkingFolder();
 | 
				
			||||||
 | 
							if (fCheckRoot == null || !fCheckRoot.exists()) {
 | 
				
			||||||
 | 
								return fCheckRoot;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 递归查找符合条件的文件夹
 | 
				
			||||||
 | 
							File targetFolder = findTargetFolder(fCheckRoot);
 | 
				
			||||||
 | 
							return targetFolder != null ? targetFolder : fCheckRoot;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 递归查找同时包含LICENSE和README.md文件的文件夹
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private File findTargetFolder(File currentFolder) {
 | 
				
			||||||
 | 
							// 检查当前文件夹是否符合条件
 | 
				
			||||||
 | 
							if (hasRequiredFiles(currentFolder)) {
 | 
				
			||||||
 | 
								return currentFolder;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 查找子文件夹(Java 7不支持方法引用,用匿名内部类过滤)
 | 
				
			||||||
 | 
							File[] subFolders = currentFolder.listFiles(new FileFilter() {
 | 
				
			||||||
 | 
									@Override
 | 
				
			||||||
 | 
									public boolean accept(File file) {
 | 
				
			||||||
 | 
										return file.isDirectory(); // 仅保留子文件夹
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (subFolders != null) {
 | 
				
			||||||
 | 
								for (File subFolder : subFolders) {
 | 
				
			||||||
 | 
									File result = findTargetFolder(subFolder);
 | 
				
			||||||
 | 
									if (result != null) {
 | 
				
			||||||
 | 
										return result;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 检查文件夹中是否同时存在LICENSE和README.md文件
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private boolean hasRequiredFiles(File folder) {
 | 
				
			||||||
 | 
							if (folder == null || !folder.isDirectory()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 检查两个文件是否同时存在且均为文件(非文件夹)
 | 
				
			||||||
 | 
							File licenseFile = new File(folder, "LICENSE");
 | 
				
			||||||
 | 
							File readmeFile = new File(folder, "README.md");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return licenseFile.exists() && licenseFile.isFile()
 | 
				
			||||||
 | 
								&& readmeFile.exists() && readmeFile.isFile();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void cleanBoBullToon() {
 | 
				
			||||||
 | 
							String destinationFolder = getWorkingFolder().getPath(); // 替换为实际的目标文件夹路径
 | 
				
			||||||
 | 
							// 删除旧文件
 | 
				
			||||||
 | 
							File fOldFolder = new File(destinationFolder);
 | 
				
			||||||
 | 
							if (fOldFolder.exists()) {
 | 
				
			||||||
 | 
								deleteFolderRecursive(fOldFolder);
 | 
				
			||||||
 | 
								fOldFolder.mkdirs();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ToastUtils.show("已清空 BoBullToon 数据!");
 | 
				
			||||||
 | 
							LogUtils.d(TAG, "已清空 BoBullToon 数据");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean loadPhoneBoBullToon() {
 | 
					    public boolean loadPhoneBoBullToon() {
 | 
				
			||||||
        listPhoneBoBullToon.clear();
 | 
					        listPhoneBoBullToon.clear();
 | 
				
			||||||
        File fBoBullToon = new File(getWorkingFolder(), "bobulltoon");
 | 
					        File fBoBullToon = getBoBullToonDataFolder();
 | 
				
			||||||
        if (fBoBullToon.exists()) {
 | 
					        if (fBoBullToon.exists()) {
 | 
				
			||||||
            LogUtils.d(TAG, String.format("getWorkingFolder() %s", getWorkingFolder()));
 | 
					            LogUtils.d(TAG, String.format("getBoBullToonDataFolder() %s", getWorkingFolder()));
 | 
				
			||||||
            for (File userFolder : fBoBullToon.listFiles()) {
 | 
					            for (File userFolder : fBoBullToon.listFiles()) {
 | 
				
			||||||
                if (userFolder.isDirectory()) {
 | 
					                if (userFolder.isDirectory()) {
 | 
				
			||||||
                    for (File recordFile : userFolder.listFiles()) {
 | 
					                    for (File recordFile : userFolder.listFiles()) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.dun;
 | 
					package cc.winboll.studio.contacts.dun;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/21 06:15:10
 | 
					 * @Date 2025/02/21 06:15:10
 | 
				
			||||||
 * @Describe 云盾防御规则
 | 
					 * @Describe 云盾防御规则
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -18,6 +18,7 @@ import java.util.ArrayList;
 | 
				
			|||||||
import java.util.Timer;
 | 
					import java.util.Timer;
 | 
				
			||||||
import java.util.TimerTask;
 | 
					import java.util.TimerTask;
 | 
				
			||||||
import java.util.regex.Pattern;
 | 
					import java.util.regex.Pattern;
 | 
				
			||||||
 | 
					import cc.winboll.studio.contacts.bobulltoon.TomCat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class Rules {
 | 
					public class Rules {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -84,6 +85,20 @@ public class Rules {
 | 
				
			|||||||
        PhoneConnectRuleModel.saveBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleModel.class);
 | 
					        PhoneConnectRuleModel.saveBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleModel.class);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void resetDefaultBoBullToonURL() {
 | 
				
			||||||
 | 
					        mSettingsModel.setBoBullToon_URL(TomCat.getInstance(mContext).getDefaultBobulltoonUrl());
 | 
				
			||||||
 | 
					        saveDun();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public void setBoBullToonURL(String szUrl) {
 | 
				
			||||||
 | 
					        mSettingsModel.setBoBullToon_URL(szUrl);
 | 
				
			||||||
 | 
					        saveDun();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public String getBoBullToonURL() {
 | 
				
			||||||
 | 
					        return mSettingsModel.getBoBullToon_URL();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void loadDun() {
 | 
					    public void loadDun() {
 | 
				
			||||||
        mSettingsModel = SettingsModel.loadBean(mContext, SettingsModel.class);
 | 
					        mSettingsModel = SettingsModel.loadBean(mContext, SettingsModel.class);
 | 
				
			||||||
        if (mSettingsModel == null) {
 | 
					        if (mSettingsModel == null) {
 | 
				
			||||||
@@ -109,8 +124,12 @@ public class Rules {
 | 
				
			|||||||
        boolean isDefend = false; // 盾牌是否生效
 | 
					        boolean isDefend = false; // 盾牌是否生效
 | 
				
			||||||
        boolean isConnect = true; // 防御结果是否连接
 | 
					        boolean isConnect = true; // 防御结果是否连接
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 进行盾牌层数预计缩减计算
 | 
				
			||||||
 | 
					        int nDunCurrentCount = mSettingsModel.getDunCurrentCount() - 1;
 | 
				
			||||||
 | 
					        LogUtils.d(TAG, String.format("nDunCurrentCount : %d", nDunCurrentCount));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 如果盾值小于1,则解除防御
 | 
					        // 如果盾值小于1,则解除防御
 | 
				
			||||||
        if (!isDefend && mSettingsModel.getDunCurrentCount() < 1) {
 | 
					        if (!isDefend && nDunCurrentCount < 1) {
 | 
				
			||||||
            // 盾层为1以下,防御解除
 | 
					            // 盾层为1以下,防御解除
 | 
				
			||||||
            LogUtils.d(TAG, "盾层为1以下,防御解除");
 | 
					            LogUtils.d(TAG, "盾层为1以下,防御解除");
 | 
				
			||||||
            isDefend = true;
 | 
					            isDefend = true;
 | 
				
			||||||
@@ -126,6 +145,14 @@ public class Rules {
 | 
				
			|||||||
            LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
 | 
					            LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 检验拨不通号码群
 | 
				
			||||||
 | 
					        if (!isDefend && MainService.isPhoneInBoBullToon(phoneNumber)) {
 | 
				
			||||||
 | 
					            LogUtils.d(TAG, String.format("PhoneNumber %s\n Is In BoBullToon", phoneNumber));
 | 
				
			||||||
 | 
					            isDefend = true;
 | 
				
			||||||
 | 
					            isConnect = false;
 | 
				
			||||||
 | 
					            LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 查询通讯录是否有该联系人
 | 
					        // 查询通讯录是否有该联系人
 | 
				
			||||||
        boolean isPhoneInContacts = ContactUtils.getInstance(mContext).isPhoneInContacts(mContext, phoneNumber);
 | 
					        boolean isPhoneInContacts = ContactUtils.getInstance(mContext).isPhoneInContacts(mContext, phoneNumber);
 | 
				
			||||||
        if (!isDefend) {
 | 
					        if (!isDefend) {
 | 
				
			||||||
@@ -139,14 +166,6 @@ public class Rules {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 检验拨不通号码群
 | 
					 | 
				
			||||||
        if (!isDefend && MainService.isPhoneInBoBullToon(phoneNumber)) {
 | 
					 | 
				
			||||||
            LogUtils.d(TAG, String.format("PhoneNumber %s\n Is In BoBullToon", phoneNumber));
 | 
					 | 
				
			||||||
            isDefend = true;
 | 
					 | 
				
			||||||
            isConnect = false;
 | 
					 | 
				
			||||||
            LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // 正则匹配规则名单校验
 | 
					        // 正则匹配规则名单校验
 | 
				
			||||||
        if (!isDefend) {
 | 
					        if (!isDefend) {
 | 
				
			||||||
            for (int i = 0; i < _PhoneConnectRuleModelList.size(); i++) {
 | 
					            for (int i = 0; i < _PhoneConnectRuleModelList.size(); i++) {
 | 
				
			||||||
@@ -174,17 +193,17 @@ public class Rules {
 | 
				
			|||||||
            // 就减少防御盾牌层数。
 | 
					            // 就减少防御盾牌层数。
 | 
				
			||||||
            // 每校验一次规则,云盾防御层数减1
 | 
					            // 每校验一次规则,云盾防御层数减1
 | 
				
			||||||
            // 当云盾防御层数为0时,再次进行以下程序段则恢复满值防御。
 | 
					            // 当云盾防御层数为0时,再次进行以下程序段则恢复满值防御。
 | 
				
			||||||
            int newDunCount = mSettingsModel.getDunCurrentCount() - 1;
 | 
					            int newDunCount = nDunCurrentCount;
 | 
				
			||||||
            LogUtils.d(TAG, String.format("新的防御层数预计为 %d", newDunCount));
 | 
					            LogUtils.d(TAG, String.format("新的防御层数预计为 %d", newDunCount));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 保证盾值在[0,DunTotalCount]之内其他值一律重置为 DunTotalCount。
 | 
					            // 保证盾值在[1,DunTotalCount]之内其他值一律重置为 DunTotalCount。
 | 
				
			||||||
            if (newDunCount < 0 || newDunCount > mSettingsModel.getDunTotalCount()) {
 | 
					            if (newDunCount > 0 && newDunCount < mSettingsModel.getDunTotalCount()) {
 | 
				
			||||||
                mSettingsModel.setDunCurrentCount(mSettingsModel.getDunTotalCount());
 | 
					 | 
				
			||||||
                LogUtils.d(TAG, String.format("盾值不在[0,%d]区间,恢复防御最大值%d", mSettingsModel.getDunTotalCount(), mSettingsModel.getDunTotalCount()));
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                mSettingsModel.setDunCurrentCount(newDunCount);
 | 
					                mSettingsModel.setDunCurrentCount(newDunCount);
 | 
				
			||||||
                LogUtils.d(TAG, String.format("设置防御层数为 %d", newDunCount));
 | 
					                LogUtils.d(TAG, String.format("设置防御层数为 %d", newDunCount));
 | 
				
			||||||
            }
 | 
					            } else {
 | 
				
			||||||
 | 
					                mSettingsModel.setDunCurrentCount(mSettingsModel.getDunTotalCount());
 | 
				
			||||||
 | 
					                LogUtils.d(TAG, String.format("盾值不在[0,%d]区间,恢复防御最大值%d", mSettingsModel.getDunTotalCount(), mSettingsModel.getDunTotalCount()));
 | 
				
			||||||
 | 
					            } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            saveDun();
 | 
					            saveDun();
 | 
				
			||||||
            SettingsActivity.notifyDunInfoUpdate();
 | 
					            SettingsActivity.notifyDunInfoUpdate();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.fragments;
 | 
					package cc.winboll.studio.contacts.fragments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/20 12:57:00
 | 
					 * @Date 2025/02/20 12:57:00
 | 
				
			||||||
 * @Describe 拨号
 | 
					 * @Describe 拨号
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -161,4 +161,12 @@ public class CallLogFragment extends Fragment {
 | 
				
			|||||||
            _CallLogFragment.triggerUpdate();
 | 
					            _CallLogFragment.triggerUpdate();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public void onResume() {
 | 
				
			||||||
 | 
							super.onResume();
 | 
				
			||||||
 | 
							//ToastUtils.show("onResume");
 | 
				
			||||||
 | 
							callLogAdapter.relaodContacts();
 | 
				
			||||||
 | 
							readCallLog();  // 窗口回显时更新通话记录
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,18 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.fragments;
 | 
					package cc.winboll.studio.contacts.fragments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/20 12:57:50
 | 
					 * @Date 2025/08/30 14:32
 | 
				
			||||||
 * @Describe 联系人
 | 
					 * @Describe 联系人视图
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.Manifest;
 | 
					import android.Manifest;
 | 
				
			||||||
import android.content.Intent;
 | 
					import android.content.Intent;
 | 
				
			||||||
import android.content.pm.PackageManager;
 | 
					import android.content.pm.PackageManager;
 | 
				
			||||||
import android.database.Cursor;
 | 
					import android.database.Cursor;
 | 
				
			||||||
import android.os.Bundle;
 | 
					import android.os.Bundle;
 | 
				
			||||||
 | 
					import android.os.Handler;
 | 
				
			||||||
 | 
					import android.os.Looper;
 | 
				
			||||||
import android.provider.ContactsContract;
 | 
					import android.provider.ContactsContract;
 | 
				
			||||||
import android.text.Editable;
 | 
					import android.text.Editable;
 | 
				
			||||||
import android.text.TextWatcher;
 | 
					import android.text.TextWatcher;
 | 
				
			||||||
@@ -27,24 +30,39 @@ import androidx.recyclerview.widget.RecyclerView;
 | 
				
			|||||||
import cc.winboll.studio.contacts.R;
 | 
					import cc.winboll.studio.contacts.R;
 | 
				
			||||||
import cc.winboll.studio.contacts.adapters.ContactAdapter;
 | 
					import cc.winboll.studio.contacts.adapters.ContactAdapter;
 | 
				
			||||||
import cc.winboll.studio.contacts.beans.ContactModel;
 | 
					import cc.winboll.studio.contacts.beans.ContactModel;
 | 
				
			||||||
 | 
					import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			||||||
import com.hjq.toast.ToastUtils;
 | 
					import com.hjq.toast.ToastUtils;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.concurrent.ExecutorService;
 | 
				
			||||||
 | 
					import java.util.concurrent.Executors;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class ContactsFragment extends Fragment {
 | 
					public class ContactsFragment extends Fragment {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static final String TAG = "ContactsFragment";
 | 
					    public static final String TAG = "ContactsFragment";
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private static final String ARG_PAGE = "ARG_PAGE";
 | 
					    private static final String ARG_PAGE = "ARG_PAGE";
 | 
				
			||||||
    private int mPage;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private static final int REQUEST_READ_CONTACTS = 1;
 | 
					    private static final int REQUEST_READ_CONTACTS = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private int mPage;
 | 
				
			||||||
    private RecyclerView recyclerView;
 | 
					    private RecyclerView recyclerView;
 | 
				
			||||||
    private ContactAdapter contactAdapter;
 | 
					    private ContactAdapter contactAdapter;
 | 
				
			||||||
    private List<ContactModel> contactList = new ArrayList<>();
 | 
					 | 
				
			||||||
    private List<ContactModel> originalContactList = new ArrayList<>();
 | 
					 | 
				
			||||||
    private EditText searchEditText;
 | 
					    private EditText searchEditText;
 | 
				
			||||||
 | 
					    private Button btnDial;
 | 
				
			||||||
 | 
					    private boolean isViewInitialized = false; // 标记视图是否已初始化
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 静态缓存:全局复用联系人数据
 | 
				
			||||||
 | 
					    private static List<ContactModel> sCachedOriginalList = new ArrayList<ContactModel>();
 | 
				
			||||||
 | 
					    private static List<ContactModel> sCachedFilteredList = new ArrayList<ContactModel>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 当前页面数据容器
 | 
				
			||||||
 | 
					    private List<ContactModel> contactList = new ArrayList<ContactModel>();
 | 
				
			||||||
 | 
					    private List<ContactModel> originalContactList = new ArrayList<ContactModel>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 异步工具
 | 
				
			||||||
 | 
					    private final ExecutorService executor = Executors.newSingleThreadExecutor();
 | 
				
			||||||
 | 
					    private final Handler mainHandler = new Handler(Looper.getMainLooper());
 | 
				
			||||||
 | 
					    private boolean isDataLoaded = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static ContactsFragment newInstance(int page) {
 | 
					    public static ContactsFragment newInstance(int page) {
 | 
				
			||||||
        Bundle args = new Bundle();
 | 
					        Bundle args = new Bundle();
 | 
				
			||||||
@@ -65,103 +83,272 @@ public class ContactsFragment extends Fragment {
 | 
				
			|||||||
    @Nullable
 | 
					    @Nullable
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
 | 
					    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
 | 
				
			||||||
        return inflater.inflate(R.layout.fragment_contacts, container, false);
 | 
					        // 加载布局(已移除进度条相关代码)
 | 
				
			||||||
 | 
					        View view = inflater.inflate(R.layout.fragment_contacts, container, false);
 | 
				
			||||||
 | 
					        return view;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
 | 
					    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
 | 
				
			||||||
        super.onViewCreated(view, savedInstanceState);
 | 
					        super.onViewCreated(view, savedInstanceState);
 | 
				
			||||||
        recyclerView = view.findViewById(R.id.contacts_recycler_view);
 | 
					        // 初始化RecyclerView
 | 
				
			||||||
 | 
					        recyclerView = (RecyclerView) view.findViewById(R.id.contacts_recycler_view);
 | 
				
			||||||
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 | 
					        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
 | 
				
			||||||
        contactAdapter = new ContactAdapter(contactList);
 | 
					        contactList = new ArrayList<ContactModel>();
 | 
				
			||||||
 | 
					        contactAdapter = new ContactAdapter(getContext(), contactList);
 | 
				
			||||||
        recyclerView.setAdapter(contactAdapter);
 | 
					        recyclerView.setAdapter(contactAdapter);
 | 
				
			||||||
 | 
					        // 初始隐藏列表,数据加载后显示
 | 
				
			||||||
 | 
					        recyclerView.setVisibility(View.GONE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        searchEditText = view.findViewById(R.id.search_edit_text);
 | 
					        // 绑定搜索框和拨号按钮
 | 
				
			||||||
        searchEditText.addTextChangedListener(new TextWatcher() {
 | 
					        searchEditText = (EditText) view.findViewById(R.id.search_edit_text);
 | 
				
			||||||
                @Override
 | 
					        btnDial = (Button) view.findViewById(R.id.btn_dial);
 | 
				
			||||||
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
 | 
					        // 初始隐藏搜索相关控件,延迟到首次可见时显示
 | 
				
			||||||
                }
 | 
					        searchEditText.setVisibility(View.GONE);
 | 
				
			||||||
 | 
					        btnDial.setVisibility(View.GONE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                @Override
 | 
					    // 首次可见时初始化资源
 | 
				
			||||||
                public void onTextChanged(CharSequence s, int start, int before, int count) {
 | 
					    @Override
 | 
				
			||||||
                    filterContacts(s.toString());
 | 
					    public void onResume() {
 | 
				
			||||||
                }
 | 
					        super.onResume();
 | 
				
			||||||
 | 
					        if (!isViewInitialized) {
 | 
				
			||||||
 | 
					            initSearchAndDial(); // 初始化搜索和拨号功能
 | 
				
			||||||
 | 
					            checkContactPermission(); // 检查权限并加载数据
 | 
				
			||||||
 | 
					            isViewInitialized = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                @Override
 | 
					    // 初始化搜索框和拨号按钮
 | 
				
			||||||
                public void afterTextChanged(Editable s) {
 | 
					    private void initSearchAndDial() {
 | 
				
			||||||
                }
 | 
					        // 显示搜索相关控件
 | 
				
			||||||
            });
 | 
					        searchEditText.setVisibility(View.VISIBLE);
 | 
				
			||||||
 | 
					        btnDial.setVisibility(View.VISIBLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 搜索框防抖监听
 | 
				
			||||||
 | 
					        searchEditText.addTextChangedListener(new DebounceTextWatcher(300) {
 | 
				
			||||||
 | 
									@Override
 | 
				
			||||||
 | 
									public void onDebounceTextChanged(String query) {
 | 
				
			||||||
 | 
										filterContacts(query);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 拨号按钮点击事件
 | 
				
			||||||
 | 
					        btnDial.setOnClickListener(new View.OnClickListener() {
 | 
				
			||||||
 | 
									@Override
 | 
				
			||||||
 | 
									public void onClick(View v) {
 | 
				
			||||||
 | 
										String phoneNumber = searchEditText.getText().toString().replaceAll("\\s", "");
 | 
				
			||||||
 | 
										if (phoneNumber.isEmpty()) {
 | 
				
			||||||
 | 
											ToastUtils.show("请输入号码");
 | 
				
			||||||
 | 
											return;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										Intent intent = new Intent(Intent.ACTION_CALL);
 | 
				
			||||||
 | 
										intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
 | 
				
			||||||
 | 
										intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 | 
				
			||||||
 | 
										startActivity(intent);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 权限检查
 | 
				
			||||||
 | 
					    private void checkContactPermission() {
 | 
				
			||||||
        if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
 | 
					        if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
 | 
				
			||||||
            ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_READ_CONTACTS);
 | 
					            ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_READ_CONTACTS);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            readContacts();
 | 
					            loadContacts();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        Button btnDial = view.findViewById(R.id.btn_dial);
 | 
					 | 
				
			||||||
        btnDial.setOnClickListener(new View.OnClickListener(){
 | 
					 | 
				
			||||||
                @Override
 | 
					 | 
				
			||||||
                public void onClick(View p1) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    String phoneNumber = searchEditText.getText().toString().replaceAll("\\s", "");
 | 
					 | 
				
			||||||
                    //phoneNumber = "+8616769764848";
 | 
					 | 
				
			||||||
                    ToastUtils.show(phoneNumber);
 | 
					 | 
				
			||||||
                    Intent intent = new Intent(Intent.ACTION_CALL);
 | 
					 | 
				
			||||||
                    intent.setData(android.net.Uri.parse("tel:" + phoneNumber));
 | 
					 | 
				
			||||||
                    // 添加 FLAG_ACTIVITY_NEW_TASK 标志
 | 
					 | 
				
			||||||
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 | 
					 | 
				
			||||||
                    startActivity(intent);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 加载联系人(延迟到首次可见时)
 | 
				
			||||||
 | 
					    private void loadContacts() {
 | 
				
			||||||
 | 
					        // 若有缓存,直接复用
 | 
				
			||||||
 | 
					        if (!sCachedOriginalList.isEmpty() && !sCachedFilteredList.isEmpty()) {
 | 
				
			||||||
 | 
					            originalContactList.clear();
 | 
				
			||||||
 | 
					            originalContactList.addAll(sCachedOriginalList);
 | 
				
			||||||
 | 
					            contactList.clear();
 | 
				
			||||||
 | 
					            contactList.addAll(sCachedFilteredList);
 | 
				
			||||||
 | 
					            contactAdapter.notifyDataSetChanged();
 | 
				
			||||||
 | 
					            recyclerView.setVisibility(View.VISIBLE); // 显示列表
 | 
				
			||||||
 | 
					            isDataLoaded = true;
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 无缓存时异步加载
 | 
				
			||||||
 | 
					        if (!isDataLoaded) {
 | 
				
			||||||
 | 
					            recyclerView.setVisibility(View.GONE); // 加载中隐藏列表
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            executor.execute(new Runnable() {
 | 
				
			||||||
 | 
										@Override
 | 
				
			||||||
 | 
										public void run() {
 | 
				
			||||||
 | 
											// 子线程读取联系人
 | 
				
			||||||
 | 
											final List<ContactModel> tempList = readContactsInBackground();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
											// 主线程更新UI
 | 
				
			||||||
 | 
											mainHandler.post(new Runnable() {
 | 
				
			||||||
 | 
													@Override
 | 
				
			||||||
 | 
													public void run() {
 | 
				
			||||||
 | 
														// 更新缓存
 | 
				
			||||||
 | 
														sCachedOriginalList.clear();
 | 
				
			||||||
 | 
														sCachedOriginalList.addAll(tempList);
 | 
				
			||||||
 | 
														sCachedFilteredList.clear();
 | 
				
			||||||
 | 
														sCachedFilteredList.addAll(tempList);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
														// 更新当前列表
 | 
				
			||||||
 | 
														originalContactList.clear();
 | 
				
			||||||
 | 
														originalContactList.addAll(sCachedOriginalList);
 | 
				
			||||||
 | 
														contactList.clear();
 | 
				
			||||||
 | 
														contactList.addAll(sCachedFilteredList);
 | 
				
			||||||
 | 
														contactAdapter.notifyDataSetChanged();
 | 
				
			||||||
 | 
														LogUtils.d(TAG, String.format("联系人加载完成,共%d条数据", contactList.size()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
														// 数据加载后显示列表
 | 
				
			||||||
 | 
														recyclerView.setVisibility(View.VISIBLE);
 | 
				
			||||||
 | 
														isDataLoaded = true;
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
												});
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 子线程读取联系人
 | 
				
			||||||
 | 
					    private List<ContactModel> readContactsInBackground() {
 | 
				
			||||||
 | 
					        List<ContactModel> tempList = new ArrayList<ContactModel>();
 | 
				
			||||||
 | 
					        Cursor cursor = null;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            // 查询联系人姓名和号码
 | 
				
			||||||
 | 
					            cursor = requireContext().getContentResolver().query(
 | 
				
			||||||
 | 
					                ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
 | 
				
			||||||
 | 
					                new String[]{
 | 
				
			||||||
 | 
					                    ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
 | 
				
			||||||
 | 
					                    ContactsContract.CommonDataKinds.Phone.NUMBER
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                null,
 | 
				
			||||||
 | 
					                null,
 | 
				
			||||||
 | 
					                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC"
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (cursor != null && cursor.moveToFirst()) {
 | 
				
			||||||
 | 
					                int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
 | 
				
			||||||
 | 
					                int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                do {
 | 
				
			||||||
 | 
					                    String name = cursor.getString(nameIndex);
 | 
				
			||||||
 | 
					                    String number = cursor.getString(numberIndex).replaceAll("\\s", ""); // 去除空格
 | 
				
			||||||
 | 
					                    tempList.add(new ContactModel(name, number));
 | 
				
			||||||
 | 
					                } while (cursor.moveToNext());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
					            LogUtils.d(TAG, "读取联系人失败:" + e);
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					            if (cursor != null) {
 | 
				
			||||||
 | 
					                cursor.close(); // 关闭游标,避免内存泄漏
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return tempList;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 过滤联系人
 | 
				
			||||||
 | 
					    private void filterContacts(String query) {
 | 
				
			||||||
 | 
					        contactList.clear();
 | 
				
			||||||
 | 
					        if (query.isEmpty()) {
 | 
				
			||||||
 | 
					            contactList.addAll(originalContactList);
 | 
				
			||||||
 | 
					            sCachedFilteredList.clear();
 | 
				
			||||||
 | 
					            sCachedFilteredList.addAll(originalContactList);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            String lowerQuery = query.toLowerCase();
 | 
				
			||||||
 | 
					            for (ContactModel contact : originalContactList) {
 | 
				
			||||||
 | 
					                // 匹配姓名、全拼、简拼、号码
 | 
				
			||||||
 | 
					                boolean matchName = contact.getName().toLowerCase().contains(lowerQuery);
 | 
				
			||||||
 | 
					                boolean matchPinyin = contact.getPinyin().toLowerCase().contains(lowerQuery);
 | 
				
			||||||
 | 
					                boolean matchFirstLetter = contact.getPinyinFirstLetter().toLowerCase().contains(lowerQuery);
 | 
				
			||||||
 | 
					                boolean matchNumber = contact.getNumber().contains(lowerQuery);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (matchName || matchPinyin || matchFirstLetter || matchNumber) {
 | 
				
			||||||
 | 
					                    contactList.add(contact);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            sCachedFilteredList.clear();
 | 
				
			||||||
 | 
					            sCachedFilteredList.addAll(contactList);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        contactAdapter.notifyDataSetChanged();
 | 
				
			||||||
 | 
					        // 过滤后确保列表可见
 | 
				
			||||||
 | 
					        recyclerView.setVisibility(View.VISIBLE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 权限回调
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
 | 
					    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
 | 
				
			||||||
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 | 
					        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
 | 
				
			||||||
        if (requestCode == REQUEST_READ_CONTACTS) {
 | 
					        if (requestCode == REQUEST_READ_CONTACTS) {
 | 
				
			||||||
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 | 
					            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
 | 
				
			||||||
                readContacts();
 | 
					                loadContacts(); // 授权后加载联系人
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                ToastUtils.show("请授予联系人权限以查看联系人列表");
 | 
				
			||||||
 | 
					                recyclerView.setVisibility(View.VISIBLE); // 显示空列表
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void readContacts() {
 | 
					    // 防抖TextWatcher(Java 7实现)
 | 
				
			||||||
        contactList.clear();
 | 
					    public abstract static class DebounceTextWatcher implements TextWatcher {
 | 
				
			||||||
        originalContactList.clear();
 | 
					        private final long debounceDelay;
 | 
				
			||||||
        Cursor cursor = requireContext().getContentResolver().query(
 | 
					        private Handler handler = new Handler(Looper.getMainLooper());
 | 
				
			||||||
            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
 | 
					        private Runnable pendingRunnable;
 | 
				
			||||||
            null,
 | 
					 | 
				
			||||||
            null,
 | 
					 | 
				
			||||||
            null,
 | 
					 | 
				
			||||||
            ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (cursor != null) {
 | 
					        public DebounceTextWatcher(long debounceDelay) {
 | 
				
			||||||
            while (cursor.moveToNext()) {
 | 
					            this.debounceDelay = debounceDelay;
 | 
				
			||||||
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
 | 
					 | 
				
			||||||
                String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
 | 
					 | 
				
			||||||
                ContactModel contact = new ContactModel(name, number);
 | 
					 | 
				
			||||||
                contactList.add(contact);
 | 
					 | 
				
			||||||
                originalContactList.add(contact);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            cursor.close();
 | 
					 | 
				
			||||||
            contactAdapter.notifyDataSetChanged();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void filterContacts(String query) {
 | 
					        @Override
 | 
				
			||||||
        contactList.clear();
 | 
					        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
 | 
				
			||||||
        if (query.isEmpty()) {
 | 
					            // 无需处理
 | 
				
			||||||
            contactList.addAll(originalContactList);
 | 
					        }
 | 
				
			||||||
        } else {
 | 
					
 | 
				
			||||||
            for (ContactModel contact : originalContactList) {
 | 
					        @Override
 | 
				
			||||||
                if (contact.getName().toLowerCase().contains(query.toLowerCase()) ||
 | 
					        public void onTextChanged(final CharSequence s, int start, int before, int count) {
 | 
				
			||||||
                    contact.getPinyin().toLowerCase().contains(query.toLowerCase()) ||
 | 
					            // 移除之前的延迟任务
 | 
				
			||||||
                    contact.getNumber().toLowerCase().contains(query.toLowerCase())) {
 | 
					            if (pendingRunnable != null) {
 | 
				
			||||||
                    contactList.add(contact);
 | 
					                handler.removeCallbacks(pendingRunnable);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // 延迟执行过滤
 | 
				
			||||||
 | 
					            pendingRunnable = new Runnable() {
 | 
				
			||||||
 | 
					                @Override
 | 
				
			||||||
 | 
					                public void run() {
 | 
				
			||||||
 | 
					                    onDebounceTextChanged(s.toString());
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            };
 | 
				
			||||||
 | 
					            handler.postDelayed(pendingRunnable, debounceDelay);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        @Override
 | 
				
			||||||
 | 
					        public void afterTextChanged(Editable s) {
 | 
				
			||||||
 | 
					            // 无需处理
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // 抽象方法:防抖后的回调
 | 
				
			||||||
 | 
					        public abstract void onDebounceTextChanged(String query);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 资源释放
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onDestroy() {
 | 
				
			||||||
 | 
					        super.onDestroy();
 | 
				
			||||||
 | 
					        executor.shutdown(); // 关闭线程池
 | 
				
			||||||
 | 
					        mainHandler.removeCallbacksAndMessages(null); // 清除未执行任务
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Fragment隐藏/显示时的处理
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onHiddenChanged(boolean hidden) {
 | 
				
			||||||
 | 
					        super.onHiddenChanged(hidden);
 | 
				
			||||||
 | 
					        if (!hidden && isDataLoaded) {
 | 
				
			||||||
 | 
					            // 复用缓存数据并显示列表
 | 
				
			||||||
 | 
					            contactList.clear();
 | 
				
			||||||
 | 
					            contactList.addAll(sCachedFilteredList);
 | 
				
			||||||
 | 
					            contactAdapter.notifyDataSetChanged();
 | 
				
			||||||
 | 
					            recyclerView.setVisibility(View.VISIBLE);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        contactAdapter.notifyDataSetChanged();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.fragments;
 | 
					package cc.winboll.studio.contacts.fragments;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/20 12:58:15
 | 
					 * @Date 2025/02/20 12:58:15
 | 
				
			||||||
 * @Describe 应用日志
 | 
					 * @Describe 应用日志
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.handlers;
 | 
					package cc.winboll.studio.contacts.handlers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/14 03:51:40
 | 
					 * @Date 2025/02/14 03:51:40
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.os.Handler;
 | 
					import android.os.Handler;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.receivers;
 | 
					package cc.winboll.studio.contacts.receivers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/13 06:58:04
 | 
					 * @Date 2025/02/13 06:58:04
 | 
				
			||||||
 * @Describe 主要广播接收器
 | 
					 * @Describe 主要广播接收器
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.services;
 | 
					package cc.winboll.studio.contacts.services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/14 03:38:31
 | 
					 * @Date 2025/02/14 03:38:31
 | 
				
			||||||
 * @Describe 守护进程服务
 | 
					 * @Describe 守护进程服务
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.services;
 | 
					package cc.winboll.studio.contacts.services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/13 06:56:41
 | 
					 * @Date 2025/02/13 06:56:41
 | 
				
			||||||
 * @Describe 拨号主服务
 | 
					 * @Describe 拨号主服务
 | 
				
			||||||
 * 参考:
 | 
					 * 参考:
 | 
				
			||||||
@@ -18,6 +18,7 @@ import android.content.ServiceConnection;
 | 
				
			|||||||
import android.media.AudioManager;
 | 
					import android.media.AudioManager;
 | 
				
			||||||
import android.os.Binder;
 | 
					import android.os.Binder;
 | 
				
			||||||
import android.os.IBinder;
 | 
					import android.os.IBinder;
 | 
				
			||||||
 | 
					import cc.winboll.studio.contacts.App;
 | 
				
			||||||
import cc.winboll.studio.contacts.beans.MainServiceBean;
 | 
					import cc.winboll.studio.contacts.beans.MainServiceBean;
 | 
				
			||||||
import cc.winboll.studio.contacts.beans.RingTongBean;
 | 
					import cc.winboll.studio.contacts.beans.RingTongBean;
 | 
				
			||||||
import cc.winboll.studio.contacts.bobulltoon.TomCat;
 | 
					import cc.winboll.studio.contacts.bobulltoon.TomCat;
 | 
				
			||||||
@@ -29,11 +30,9 @@ import cc.winboll.studio.contacts.services.MainService;
 | 
				
			|||||||
import cc.winboll.studio.contacts.threads.MainServiceThread;
 | 
					import cc.winboll.studio.contacts.threads.MainServiceThread;
 | 
				
			||||||
import cc.winboll.studio.libappbase.LogUtils;
 | 
					import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			||||||
import cc.winboll.studio.libappbase.sos.SOS;
 | 
					import cc.winboll.studio.libappbase.sos.SOS;
 | 
				
			||||||
 | 
					import cc.winboll.studio.libappbase.winboll.WinBoLL;
 | 
				
			||||||
import java.util.Timer;
 | 
					import java.util.Timer;
 | 
				
			||||||
import java.util.TimerTask;
 | 
					import java.util.TimerTask;
 | 
				
			||||||
import cc.winboll.studio.libappbase.sos.WinBoll;
 | 
					 | 
				
			||||||
import cc.winboll.studio.contacts.App;
 | 
					 | 
				
			||||||
import cc.winboll.studio.libappbase.sos.APPModel;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class MainService extends Service {
 | 
					public class MainService extends Service {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -129,11 +128,11 @@ public class MainService extends Service {
 | 
				
			|||||||
            isServiceRunning = true;
 | 
					            isServiceRunning = true;
 | 
				
			||||||
            // 唤醒守护进程
 | 
					            // 唤醒守护进程
 | 
				
			||||||
            wakeupAndBindAssistant();
 | 
					            wakeupAndBindAssistant();
 | 
				
			||||||
            // 召唤 WinBoll APP 绑定本服务
 | 
					            // 召唤 WinBoLL APP 绑定本服务
 | 
				
			||||||
            if (App.isDebuging()) {
 | 
					            if (App.isDebuging()) {
 | 
				
			||||||
                WinBoll.bindToAPPBaseBeta(this, MainService.class.getName());
 | 
					                WinBoLL.bindToAPPBaseBeta(this, MainService.class.getName());
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                WinBoll.bindToAPPBase(this, MainService.class.getName());
 | 
					                WinBoLL.bindToAPPBase(this, MainService.class.getName());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 初始化服务运行参数
 | 
					            // 初始化服务运行参数
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.threads;
 | 
					package cc.winboll.studio.contacts.threads;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/14 03:46:44
 | 
					 * @Date 2025/02/14 03:46:44
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.content.Context;
 | 
					import android.content.Context;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.utils;
 | 
					package cc.winboll.studio.contacts.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/03/06 21:08:16
 | 
					 * @Date 2025/08/30 14:32
 | 
				
			||||||
 * @Describe ContactUtils
 | 
					 * @Describe 联系人工具集
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import android.content.ContentResolver;
 | 
					import android.content.ContentResolver;
 | 
				
			||||||
import android.content.Context;
 | 
					import android.content.Context;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ import android.widget.EditText;
 | 
				
			|||||||
import cc.winboll.studio.libappbase.LogUtils;
 | 
					import cc.winboll.studio.libappbase.LogUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/04/13 00:59:13
 | 
					 * @Date 2025/04/13 00:59:13
 | 
				
			||||||
 * @Describe Int类型数字输入框工具集
 | 
					 * @Describe Int类型数字输入框工具集
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.utils;
 | 
					package cc.winboll.studio.contacts.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/04/13 01:16:28
 | 
					 * @Date 2025/04/13 01:16:28
 | 
				
			||||||
 * @Describe Int数字操作工具集
 | 
					 * @Describe Int数字操作工具集
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package cc.winboll.studio.contacts.utils;
 | 
					package cc.winboll.studio.contacts.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * @Author ZhanGSKen<zhangsken@188.com>
 | 
					 * @Author ZhanGSKen<zhangsken@qq.com>
 | 
				
			||||||
 * @Date 2025/02/26 15:21:48
 | 
					 * @Date 2025/02/26 15:21:48
 | 
				
			||||||
 * @Describe PhoneUtils
 | 
					 * @Describe PhoneUtils
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user