From a9c6ad3bb47882f38dfaa6f90cbf5bdd5a28e7f0 Mon Sep 17 00:00:00 2001 From: Wang-YYu-Lu <1756892659@qq.com> Date: Wed, 14 May 2025 16:31:42 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B4=A8=E9=87=8F?= =?UTF-8?q?=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/开源代码质量分析报告模板.docx | Bin 0 -> 21511 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/开源代码质量分析报告模板.docx diff --git a/doc/开源代码质量分析报告模板.docx b/doc/开源代码质量分析报告模板.docx new file mode 100644 index 0000000000000000000000000000000000000000..626edee6bb8b8a9a5b587ee52f726c15ca9517fc GIT binary patch literal 21511 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 WH!E=91GJA&lp!6sTcyhn!~+1MwC$S! literal 0 HcmV?d00001 From ced3362da9b70a4387fdcbe4ab070971d19623fb Mon Sep 17 00:00:00 2001 From: Wang-YYu-Lu <1756892659@qq.com> Date: Wed, 14 May 2025 16:43:25 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B4=A8=E9=87=8F?= =?UTF-8?q?=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...开源软件维护方案及成果模板.docx | Bin 0 -> 21749 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/开源软件维护方案及成果模板.docx diff --git a/doc/开源软件维护方案及成果模板.docx b/doc/开源软件维护方案及成果模板.docx new file mode 100644 index 0000000000000000000000000000000000000000..0b7e6eadd93ea2334378eab53576e07fc0fb462d GIT binary patch literal 21749 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 BXbS)U literal 0 HcmV?d00001 From c5b64baae7fcff535269786f7c09a9f0fce14810 Mon Sep 17 00:00:00 2001 From: Wang-YYu-Lu <1756892659@qq.com> Date: Wed, 14 May 2025 16:45:58 +0800 Subject: [PATCH 03/11] 2025 5 14 --- README.md | 4 +++- doc/报告文档00.docx | Bin 10107 -> 0 bytes doc/软件设计模型.vsdx | Bin 0 -> 23678 bytes doc/软件设计规格说明书模板.doc | Bin 0 -> 53248 bytes doc/软件需求构思及描述模板.docx | Bin 0 -> 20583 bytes doc/软件需求模型.vsdx | Bin 0 -> 22217 bytes doc/软件需求规格说明书模板.docx | Bin 0 -> 20020 bytes 7 files changed, 3 insertions(+), 1 deletion(-) delete mode 100644 doc/报告文档00.docx create mode 100644 doc/软件设计模型.vsdx create mode 100644 doc/软件设计规格说明书模板.doc create mode 100644 doc/软件需求构思及描述模板.docx create mode 100644 doc/软件需求模型.vsdx create mode 100644 doc/软件需求规格说明书模板.docx diff --git a/README.md b/README.md index 576c717..576ec76 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ -# test +# 小米便签代码泛阅读 + + diff --git a/doc/报告文档00.docx b/doc/报告文档00.docx deleted file mode 100644 index c1badbf491a9bf57b4f36847a5c6a6263476dd31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10107 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 diff --git a/doc/软件设计模型.vsdx b/doc/软件设计模型.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..c93266f697d3de1e45c33d335942deae1fd8fc9b GIT binary patch literal 23678 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 PDUtxfC?Jb348#Kf(i`Vt literal 0 HcmV?d00001 diff --git a/doc/软件设计规格说明书模板.doc b/doc/软件设计规格说明书模板.doc new file mode 100644 index 0000000000000000000000000000000000000000..1b04b118913ebe961f4d2748072c0a1e103496bd GIT binary patch literal 53248 zcmeI52|!g<-oVd$k4u5Yf;KL`Y2uR}gn|K}9mOm${W%YF3V! zpEXT2jZ;qhWM$bhQ`StGE#GA8^i5_|X4~ZZe*gQpaNgrRd?XsqaP-H$XTAS({%5=Q z-Fwb!`&%5k^N+C~C@+($Z0fkHi3-u&Eu0I6X|9x&6R{t6xm<2Xr8sRgXHW_JjI6Q+dU+4!HLVvgjQsH7qg8`5Z z10e$j!C<%qGGPb|g-c-=Tn3{c8-_y;jDTFogUewYNSheV@d_9NV<8`|gaQ!%@f;_> zM3@AVp%98d{7;7&p=R@MKDrpBW^tUW7IXE$O=}fg)#fck3u$6CB0ud;LW;7=R3xUQrR%Ul-vR}lYbM8YY#z+A|#q?xXf2mIiKYY>ho{BvRWi5xvG?x&pgZht-O8+PJ!lM z!lrCe9y`_30=`eUeC0_w5{| zUiIN9V@d``8CQmLl(8kBql_<;Im)$WaFj7-K1Ug6?%^oc+r>r19z>!YIm#Gwec`0y z*4KQO8|zxUovCmqJ^Q0H= zH2Xzqds2ow`6I_q_#<&;OudZWa1uS^Y&8#xj9xpNW0B!rNS@5z#2uF?Cp7-_FS1(S zeC5rpJ=!(D`4;rw?S}_4a0~Ww6J2iv$+MJECSb~k^G9?z8YE9MKJk8aFDdbn8$x}E^);;KxC6^W6I^)axJ;G#NSnE z7dNR-mr_5nsWDR0lNlK%5i_0RRB|zy8B!rWVkEA}GKATK%$t14FZDJF33~CjJF}HU zYK!17j!D#qM59iKjyu61(&~*%UuHAu{7d9)05h3nTvLeEm-8e_qZi@CHqZz+0GA}< zW{^VNjDvEWzzk%DG4rTfTnQaXuBDu%ETmTww-cEx0(6%QV=}nx@!!XiWpr?mXm}O&hM8MD5AH-W!|g)^?P7+rG8{b@Z$2_4VWr-}Q`IwXzA- zIA-`Bw}*&lH0U@c?vd)!+)H!!8tvQdUHvyGtaa5qLR^ESQ^!bO?#sAb(j&NyzjM=n zr@ETc3T{2jqv_-CIGm;%$u*k{sJ{FP&0x^o$UOmh?BH>W9ILSm&HpP}oO z-q)Xb3(qk$fkafgk#wFv+nw(D)Ntt$0ySlH6>$WPq5O-9xP!uye&%ZAk-Ms2+ia!W z?yE;3HgFqwTRo;%TT)!gxbtdTTcFeAw}9)&XnCfX?bJ&dAsbD@Dgmns*LtmnC0nC3 zXG#fF-!Ju7<{eY2GVhc!s_vBf^As+DIjj5?{|KM|^fV&W>~+Voo?3I~n&(#aFFv{^ zvZyG_cPww$PYOFuiFKK-;l@4P!Q7)oD{{Zi-L>ZOaS>`=!FRc#O57x@`|RvA3&`{|nJ$M2t1u`X1}JzgmHpJ)2N2=0}Slt}JdQvP||p$z1h&z#lH6VycRE_!kl zmtx~@DSu;(u$erC9M0Xr2;*)vi~Ac1HG{vMxkJq(g-OhalH;bdy zIJLTokcq)8&xpVkDI|1fsK+PX+1@#;q!x31k~)00%Ctx5Y`KDA<9T_lpY^&?TT zRzAt3Dm_bGrIC2`BTX+&nqH)O+t?vlbtxB#Q$LcVXp*Fm>a)4F@{Aj9Ev$<)60d%w z>0K#J5-r>8pYL8eZc1IG>0NKq^r@1@-NH?Yj+BHJug$w7_pA|hk*kj;SFe-mdHQN{ zNt-q0a+XM0t<4+0Ii*gL^{pq#dh^W3-81*p^cQ#;N&M=XbTVbsn;zMeq*`~m**}&2 zeW`PbjQVwvO7EplPAapP?#Y-Tnu}l1d*ZMK6K|=jM0!tsauS(6wMZnrZTx~Y*&
AiQ#NwmM-Jl(9WThbHH zDV#OQkf#o%r1#(_Cym*IODRcD{Mq`s*VI)Sy$3g?k(p6=)f_9L#yls2U#!cQEL$aW z=WbJEJav|sbD&h>%DhPGsW}s=8UD-MpUa&kroS0S>W@BO(BsX^xiPET6w}vPBJ*(b zzQE!rUsADnZQe&&-{nRaE$i~!%d&YqHSYCX_gQtku2&pgrfx}}A#?CpS8(p(iFb_n zxqNM2*YQ7>4_Pu~i7AUdQ_$rw^DF7deE#L!lAPz3zOYn!7c;Iou1mb;>nBW+G2R_7 zZQ`n#FXuW-T4sH=>4GU=tg$#A8{4v|)wqQ>Oqo6;%gHS1+i@1hyqq4JURiSa&0M1 z(AQ|lZfoFx(>+_n6QZDV)Mlip5BJ=`Usekyx^>B5{QQ)Vx}`U+>sm$_3X4$A2| z-Yk80YW=b#o|&dQt@u$=yT$E=bRh0&JvZ?ZF$%6;wK}sI|uF>XvWva zN0GP9h}5jLdAih6#^gpJ-entRT_Y~xE;Gma zm>EGYT3yomxFvFbx@O-}Q)($iXNevn-1TMdCs{9Sh+hz#dwisXGku*U7p~v1uG6$N zqrzP!1+PuIJ^T4_QZKGA95uFZ<)9pC$x?1|ZST=Zt}8W3%F-OQoF!7)?)0P$dActt zJ3i9lkn76`_stD6*3HZLsmxhYx@BF#@sUH8guAN4-;o=LO#1j_$`h2AfIMrmy=9T> zio4Vw^O_b%wTnnD5{eurDvRo|N5AS4@*=5M=ik(e$RxgB<~~DhI7%sqtsr0Y{#fCg z=v+$jsj}9&k$KJ%ks{nB@-8V8U$ivyo)O}wTur;QhhWsWfhG{E$N=s zXU3o`8LNDimAKzr@N#bPO1E#dRO0i>sa|2r^23&$I7E;1gpfJK^5gHo zp$-xYC9zNv3nj5ocVcmpSW4KkOEU>o*YN&i_jYe8d2kD@q6ZFbZRBaf(DtTV2Te{7 zPXr^Q^%h696P=X9a&W>5SP83PE!+s};U?G!x4~A}2HRl=?1bI$Fgy-V!gH_>UWM1- z5PS$f|MbIm-+uGemtTDTe;>ZP|1U4?*>&eFH(a}TcHvlglhT)InLX4-`PfjC4K>+B zO%2KI?14k$s7f_tbgQ>^UtjrGF_Rs6ZwJS0Fj=mAOa?dONye0k6A-)*~j<<(0TFI+J1s@XHAPn}XYX~MWG$6hf?UZ29$ zmXBZJ7gLm}BCdLwHw@e_t{4?d{b#uPs#m_;lwHa{8B(AR^n+ALgLKG%!7vnt0S{5t zaNzNm8VRFe4CF%rOoYi$1jR57X2Beo3-f^o_^K4jU@4Tta##T?VKwkrUEK&b!A95& zTi`a>2HRl=?1a1FUbr6~fCphWXnoB;Kl$i`_y70Zx8Hj6@2~HF$ktzxO&;b>0`16$}9L)ruocF6*LcK z!F*6Lj-ee@4c9ilTrUr^*t3~^42K+;z~~up%$D9ENv)jQ%c<{j zsVTAVaQ;%Yk!$)>`5Pnp+5tOZH#`iF!oT1!907R?>uWd)$KZSD!P`>~NP=|8fTN$i z`?nYO{OSH3o3C3ut8h%#0C~;I%hZ&;t(1_A@4s@XoJqB+zRFBRi{1vqA}ED2SPJE^ z9GtKMo`k31X?Oz;z(Hur+jHR%3C-c#!ymrAfA52L-+t5eOJ)_09g%r)ugV%wpRFpe zwCbyrYS!7hwYP>_vs6pbSv15zYiJ8uFdRm}M3@Xkumx^|t*{NY!w%R9cf&Uy9{9_% zkKDIy)0*XrW*1(O*!8RVn?Kl95hu)e20L!G)ZQ_-TgGFS?`;6d08 z55uGII6MhY!BIE{-$NK5>NJILNQE>wcKD;WU)%Ti?|yUBs-<(sjT|;mKEAAB>a%1T z;_Ry7_VzW$F%>O(ONR^?44E(#hQV@h!V1_9J76aqfP?T3ya)e)LvZZyq5XRw{lm^J zM*p8bVz4>%8+G7JDwk8&;u_Y>K}Cz+K7@}UmM;$4LkH*w{UH_Rz+9LQC9nuep$wM7 zZg?2J`Rx5SUVP%gd+yk@c6mwR6frUD`5l}^o-qyoSun{)H7Pt+z!ZvsV4!}V;3`d{>I`biC9CU$rNC24w zyz=C(yS8q)j(dRo5koGPO5m@}2A0SA4Aof2^yhA>rRc01^Z*AGK`~5&QYeEJuo70o zT6hYchG*e9*at^GeCyS{kKDWU#`1+TCy&XwMAqBzZyHX0XlFis;)!qd1E`>|`I$js zo_e zqyAM@-8hrvX@2kyM(M(2{N z3iC2AO0Mn!8fSMhJM-7?`JU;X`Z80|qPGO-2K^xw(qJykhZ0x>rBDV-p&XXOYFG>M zW$-q59JJp6u3e_Cnm9Hut-2EUIP0Rl>CjgBcq4F#@!cc0Pr|oRV z&?utTcr(QP>v-+HmA@;WVZSQXR}Z6Fiq4*dzrw3<1S;St9E0y6h%ezopfkilALs|^ z@cBpYzVOifJAbq3hQ)s&I&9yHIUaO@9^imdD1)_dBdmve;ePlYeuVz4 zeDV2Puf6!p?{8hbWbsu~FCWmoTG_u^Kj5u7Z@auVQTv!syKjB#^w+F+DoS*i3L{|* zsya}+)wn4M>%1ZgA;z#i|2dYa!j`z)h%D^mI~c+M7JE)E&tLjpXruQ zb;}33qQ@WX8MWN8^OI~SpRWs6gZxH_M;6o9)%NVuw)rslnmEkt*pfqehr z(bPKmC;;D1)O8A>jad%;MmAGzjZT3d{(e`p9sOO*h zcC%1(Vh_Y{5&6u_gLb~1+xvDt+qbjp%^(Z8>UDq`XnVrS(PFh(f;n1kwmv}|Z9%p} z%{c}I+nl!AYo)S^-o3y3If|P{tMzD`U+CrcPu=o?ZfQI}O(hW0Nt&O#531|A3Km`K z-+4)!t1<~yXPm_8mKx{&uB;kf?@(-M>>Vn52W8X0?NfaB6JWcqq5npQhE@XpTBPpI zvfb$13PBJ8jqTq7< zE1T#%71AIb8r#2z%1@@P`-a{hz@We{EiOS2of4P#6YT(AfSx zRPL({pNw0BYyYD2;V=U7pt1dX=>H71=xAO823lrU4r6NG@*j{pq+2qjqrSmCTmi7unoH}QuyZkM9i`BaH|py z$`?3Sr6cEJB;8a3`%B*pxZhKGU5P7lo+yn+0|;ZL;UG;h#T0!enC`#y7>Ino zH0{$BPs&5T*3&Fa@ERO~3Xn?K9PHqLG#C!!VGfkTdhi!dPg~CIg#9Jy{I|y&O3{Di zvMP>rJZ@uElcrx^s1$pUu>yw87H3P0qlDQgwH0f`wpEvAT3IE>bJ6Z`nUTglR2$Oo##*x$x;hKj ziIHXOF3s%5kLb!;m9E*7n&~Ey?pa(jdh&LQg>-`~F<_=`QL&_ICsnJl!fg)63E17s z*XAjkq-)9ZA+Id5)>+xS(w$(g2V!2p8fBzkB`vXZ6Q>5GeeJqaKJa&U%Xo&UgWGnl z`P1}^oTJ9(W=rTSH8t%U*FzkuLj|c>MX~FPSN1RF0|F%re+07Tht<%TTY@xoJo{_c zS1Jvw^eAFNE47h?Hb;%^vV;$mYAGLwYHyT}K5+>$>c)B3yt|H%8>up*GG0_I7^=pD zOmWVV7&6tV%5RW5QgZn?yXwvLBUKAEGGkXzl=EPd0+1MO{Kn{I#E2$_-4^9sA5s7k zqm>y$vV@sqHLoFBi&QO%v7RMcGHnGQF=EXaHKgie#E2orqTncJS+fG*bzNmA#t2J) zNxsrp)q*Xt%lMp+?c3e;;F362s|i!qzRl;_E!HqfGTK-}IZJgU_CyQ%tTGb2$wH;N z5`RLREFj|c&nWxkumX@6F=h<>#Z*foEisb%G?E%&PGBTPJ2OU& zvhQoeXh)2+kSM1;q5$}*T-}!TklJf0lH@B5J5*oOzj)0kMJ?(#vc0*04a>ENaRqd2 zM*maYn<-^i=cVmXuUqVrM5PfeSr*CQz$#pjz z-+0#~7T8hg3E^{!%T>8bO|T@W%Zc+9N7Fb$Y)TJXx$87xN76!REmr!=Dq~d{n?0XOSYK^<&sq8YT>C(Fm9~$J*UuGHUMq54WU-3#wH%fIP-9r?dnTGU^K~-tU z-t5(zH7H{b*iO!BsEZ7j?3BP-7TTJotO(knew*ukk=R^Bpqt!QjkTLlIT}< zgKWSmn{diTjItS@Y{-@t>E2LFHs_HIT4a+B*{DGl>z4)FWzlX~xLFqOl?7a75l>mj zQ5N%)1^b9j8M+4yqA|y2Gy{UuFG%memMlON#wF=rm1+m=ffeLb2j~cP=meeN9FVqs zE_4COi!2@{d67kgWFZ+@Ohl2V5D158XbT-64idltDbOF}u;It3e)E$wLddag`g^dqB!j7N?g*s%61iS;SJxp)2CV!+9We z{e0*KvP^LgxBz6_kUA%|q$ebU^yw+k8~T9s0sY`YklywpNQH|b4F*6u41^3A1cTuc z$b=!l+(lgqQa>*PsrRz6l3}EvFj9Pq`k*ceT2JM-T0?BC;$*c2xq7HWV;8BX-NEQg zEOK3!D^E>TGgYCQhpMtTF61~u&BkqlnngO@NoNIBp3}RMYp$X#wW{*{s|5&!ak5n-+<`rJwCew)S$!>Xq zD?^h>Or()-hMa3Xq?5_Y+y`HG2E*B4GIZhg&nxv{Rr zTaJ`On8qXVi3HW>FtGg?k==@%|A7mJn;jqfc7+Gb` zt2#Tu30=5*Qbgy^rXme)bx42fznvgk_2S*&p8tx@i2*WDf;WWu{>Xkmve%F75hMG<$lfqA&Hh<0lb>|UVcqhfZuz@z@lfRBy3a1%@>|`) z{H)q+sy;=0-Ey^V@qZpE56+5>2Xc#)+`Q@!1)6kLO}nUOgDpHJa6h8?WiE;iog+k-vZs&SO3EHEviFPZ`(p0-BKy6_UN5poi0lm_`+~?V z*0*}OeyUqMR@Ht*_wi`1&*(mTbc=`n@78^`>XsXH%eA_tRJZszuc^s;D)YMQT67?~ zsC&%%i4h^Xl)YVKUl-ZaMII%{ULdj$i0lC(`+vxOAF|hnJYtZ2BINe^m|m`5=$4Ol zi$|~iH{Ito-QrOhJo@f?^k5$Cf1U1goo*@7E&BPd-|p(JHEIWu>ZLELnU0DOUCLe` zvd@R?@ge(rn0rEW;1P-)%zYqEy3IePE8||>;-O~$ZC;P^E1&z)q|us@E3y?Mdx-JK zy>cq7J%aby)_tXRI%;dvWYuxk@*ehG`v!E{6&!lb`t8A;ImU53mwvd-u3TH&U59K* z!>uZDeIH9xhsE`}wegw3uUz*|@#XD26|;n`q-WS^c`-*`7~rw+%&B+p`tTm(nU&$7 zc2W&Kfe_;vT9C3eZ?4JZes{zjQmLydtBg%O%yY_4Jdo|i1K55%P`y}PsjgP{s7KTb z)|afU?5*u*+0V9jv8QylIIIqvBiPZz(aaIyh;p=Wv~ske{#jk2t|qQpcHx`{3dW=HPsF3r{JyJA-PI*^qA$)-gIeUN z#8HLnjy}`W(N@#d7bSDl_-huakGn2c7mr<`l4h?^tuMYoO`ot+UC`=2_0=W!skc)f zP>1?Hq(suI^7pDoB41LgX6;ws_jpg;Z}~`FZ~aKUIj};NHa{!kXz9*~SHf=ZkvRN< zVRtrNby@KIYer0u{riY1(>fL6edYh}T3VD`p1fbNSl&!*H_y<+Qb7U$}p*K>T3}aPI zjd)VhQvN))u1Me*UFmKS4e$`4r)nnqJ*z!TN?OQ|5UAy1o2cy_T)%`035a_P^Z*AW zLQlwnv9JIZ!XhYzEwBTggr{H+JOl5;=MYSGLLm&ALOdkFFvx;z$bs3g5H`Tgun{)H zZg>g~!aMLT{4e|j!BpOk&#rH?1tyzefR)Agpa|BN?O4A&>eb!1F~Q=%!T=|02aa~ zxC0)8C*VnV3Zz=LjM(UEIU3I0=-Tx3rl-&J^G)THH$Q3^KRdc}*omB#yIj)UMDR05 z9zUZ@;#a*s{HmA8FL{0Vm&mVso_@XYN#>t}P)Qzsy|MSkRpR#~M0Gp~*%#Mj+{M>X zi(euQ+muD5=#30=HAf9e+*0;6e#Yvfr6@V5mQrM`mc*UA-lUdjNRp`ec}wY;JH1pK z#I2T6N=Zs92?YGdB*HjqDK9CxYAL-X>8bg7=dPDuN%XwAB{8+?Kwf|Hd*@m& zN$Zt*}o+MFj)%i}Q6!bdeodaE#z8>*(?Icpms?+o?%M`yk*JF80;=fcp zYqMuLOU?B!NpHWBB>VO0RZDucm856h^!6b-td`MRe*d-0e>wWkm;YAduRcmkt(MMP zm;Phvy@=jErGELY`Ms$%{(SuDLwY-ZaZ*$c{i@De*o9{pVf?{vY08^_;O5QuxOrm> z;m2!@RL=8Zk{9c+KLsyBM+StFO0MSk1OziN8UUN&9jKh7RZXHQ2X15jLlVZALNIxq z#dsxy-$p1E8B>g@kW9{umr+}AlsOU4%TM@z&Dn(M03E>&^1e+c=nUsT9GnYXpew|~ zc_4GK^PwAbhaPYN$lNXwMtku#cHw!-(;u(m=gp_MdBgpk+~ZYY<$N$q^uaB-d9x3< zH=#Q^D63=@$LAq}0?q{4Tu|O45}ml1Rt8bxlZ@9`X7YEIn#{{4^WmOu$6NL1HJ8P_ zO*31K;gydWYC5kmOv5&n8_Nvdx|y!7P@{MQCmDMlFFVZSZJScgXTmgU?jr2dh|`mB mGYMZzI(eKY@>+z%>xqA!5l7OwjC6~LbrJtuX_Uf$n)!bSDcAhfHXZ3m z7C(jr5@adJZ5(8C&=5_D$Vk%2Qh<-SW{FS@Jka}TWX%ASa%aG-p>f=5KK9{uxc=@4 zb{pH9KjOsC;jv+>rgWwUQR4JW=~_Jt*I`6KVpSX$iIucKkqFSKLFLjq*>Cy`s~o=< z*NlmNz?p(1q3f8<4t2Mxs%Xuf6DY@TMMJO($ftVU%iS6p&d(ouHcqBa>!7OlZ|IQw zFexq);%X_mCR8?I+0z-pPlM$8WDYYAam)P}CFHhUmlKaGFf(y$EgX2^#V~WencxT( z&F*{;Zko?QfLH;Y*Mr2^vU=++0_p)!7SDmOrgJ-i)kk(A6*c8%kNe~tq11u|ly(%N zo7={Z_g!`b`g$^`-kuC(O3iz(_07M;(6c6Q#1(!rCB&=g)+kb8)~{+B#0*E&_56vq zJ_osI-IYcDil@gZjIEO8^%@ue;Oz|s8z8BVmwGR~ zM52~rFYqx#$cYpOg55ZJQ(Wp|0dOamlE=9ug98h?_%D1o+a*+1bgxD{T)HLY#rT$^ zC`Ehl_s9)a%e+_Z^BlucUpal+&>RCt342%Y48Kno1?mmR`CL5GCnCu~2nqq?vZ$q7 zUfi9@kqNbGetxBM zo;*L2V^V{jZX>Q)t)N$O&^&y&O&t!=QPJB1qBPS4;8XB}Og?n%W0Zu|OB(7`@lm3M z#Lg8dL7t?ckMS0bh8U<);gjn|4?${jAfZI;DWO2G%tRG7nN{@F7fR0#Kw$@D=jVaa z*Q?8^&P9RFF@lFf{q{V|V}Qf+jW4Ds&~_erw=YXckw-z3ho_W+SlUB`41K>GE~HH8 zayDqELg;cnNC8EP&%s;#6Qyr|a2`Y*m}NXU>BP`zlRE;ya9ux)9cN(#pv20To{2Q) zTG$Al%1^! zNNJ*>Z!%9|N(~4p1f!A<>fjt*8u8JNNN5;;8B*ehnnE11YZ5r7&+a5BVcT#D;5`}$ zlzT1BqO3UVe#?hFbY(alp&mv%2B>^d!)5wpZ@{U4fO9>rM_l-Eq~ zb=;wtCs^p{_NsC+PK@Geu7IZSRdqjZEYZHo`_IpxQ-=j2lV8KLO5Mf>5HRx%xWF`Q z5Jax?tCS4#hu%2yV{QA;cOj&J*TEI%4>1C#0p#^ieaHW1kDW7#5D@_U?MsHAoq*hK z>aooMA$x@=#5P$!m?2Mx5el*5MA1+du^ENG0tRevL`NpQ9adldpx!MYh=Hl%u_9Yb z3&|X1$p8m_x>v)1otuT|XYB5nXx2Dg640uehoO*+C$khjdNSYQs@B;GH^QQu=TwOv zHyBa%`L7?)XzBuR-bfRdyI}#6#w{BIJ_d}MyDda(n!<5-rki}=2tCZZxOG%d(&J2} ziy3}Av3FBp;P~Qse;oX=YNV$>_ayY>1_m0$6}Y0HmJ)H1pdWN*=z^$i)o4+_Ueiyb zy1T!MAE(3xgLiIhq+^H*HcRk=X~XEF&K}halc3<5iG<3k`8V_K8}YiQk>6{<(4p6odpkBpcR)av9pi4(kfwnlm6jY}TJEKB`?lqUK;d_QXYZR7zK( zuB|X7XdlH|-83ryjFboW;XLE zeme9jlC;oXOd;hqE(2rScs}fqIBMrEakO(^J@Y2(+n5Ei()=)-gxVT~zS)|DRL%{g zv#Tx>b9ciu*?3E{4?6ZADTV5 zowS1qQ=_NZIqO~GE24Z1@^(Kk=PZ-!XQL7NRLH#NtllLYqU@9zo80-NZ+e$%dbdd`hi>IgC3onrp$( zXE)7b;U-n@w8k1PJ^kT;@2t{TrKzz1gtm7KsXyu}!1C77^xU>!?_meVJ|^6$ZX;cAKyi4p7t26Tpk5AUx>q-_k;C&pz5sBxBg^>BQE6CY6o zedXpXiWtlSv~`@tgwlYv!32(TM4HkM}B_zQTJSmj7wzj>J7iu)n*n z%b)-N*Z>fKzYpAh7`s0Y-~Tau0pI=D_oM&cUfSX$#e3=gF#L8brQr#|A6Nl!`e$HV@Ni4%FH1;&yp-P;LF9&12M=RQksMG7{sNu z{7C=ZaFBz9Ae#uiMSOg`L3+ZbPPD+(jlV365z+$w$*o^v(tCqchD*dv?jtqplFWSB zejiq)PoHj+uInl9G?8=-EmFx{etBjD*K?n`qN4gYKMF8FMCmvkeDUH5Egu7od2h({ zxNokqj+mQMWWLw}uuBb2x=AExy%EyEVjrI;gH>&Ld$|chyRr}~8f!AUx9uA06=^{;&<&CSy|azTG<=g z{bn`RC9GO5(IF31tRp47il{N$wk$$av0zU7q(Kq8$r|2$B!wlI zTwk>T9POqj8<88NTQ?Ggn8sxtXet%1AM_PL6Grq0THAr&76N`S-PgyW!`ULX+Y;BT zMRNF}qv#l$yboQY1JPUDhmP2$OJvmj(XIoc*Kkc!65TsO7`)h=Db%RFZD-dY-%?m# zyFZ+L{RX`c6KMUw&WGS!4?;g$LAs)s{YgopHZUi_#MnUXNm|W|mW%6QKC!PltCH-W`- zH`5&Z?3@!9Omy(vDEFXs7!r4tWw%Hx7oHG>ZS|J@&O%PuWktg{LTj-PPY0kjTV**` zC+`PLq&3wkU(otd%389 z4e#7=?s5H;j5CFJlUs7Z{0&pkx8itpF2U^)6=}_^Gx9ypAj2DL1@Bo?`-*D1@ghsh zZpK@?oz!maLb~ZR$ij%tB)>Eew07SZdpgS_2IxN5t4-WzEBYxrHPv(#l~&7o(nFQx zZQCk4T<$j_1fT(h#smf3(`US$d(%L<(KgkBw?6)>)05x@9{-zu-=KbSdJHWM{wCkl zKjj;Bjs*M>Qc$wQaj{@U^7s~@!p2weUA~Zm%j2Z(1|(tLX3cavNmo~I*iYEb&YU$X z9Ps(Y8{+U19vcW>1;rjLAwAz7nL~UEVYWUFfs%<^6Jl~!aC^CuBX-NvKu=}}TBjo; z(()RGOW@D253KNO`u3<1VZ=nS__LyiqtgAmAz#)K7~!e3Yd+=2yKQ^KBSf_*4vePxqZ zC9W1uG}@Bqj9qM(rgG=~L9{7-1*$Kq+G`f}Q{LLGtzH)*#-o^>nN-5z_!sD$XA6JA z<5~CxDjW$F9#XlO@u?KT1f5D}xd&-XFETE+C*{N?{+p1ulNwa#aR?T}9hvBrJwEGn z*+m6bEb-b{RT#DvsI708kIj5wT*JHCr=}iKh96FdI)^?Fj}KWP0e233Wfj<-6n5{KsJ|n?p~TxpN&cCLY6U}8|@xY zmVB&{AGvP2@_~CaFUHg;uam$h35A&rsS`qB+q-JM`-)zz2F6GFr2>mD0Z-r1zm-58 z)qKAh=xs9)S+X3ku35Cnp7>&kvUvI91oCbO$2ymb{7h~wM&H!Q?X(#eSm`t|TA6r{ zn3@+U1o;ym;1}C{JH)tg(POv7rsfDHp}Si0ubpE&ruFAI+ht)#`x>XpYL9l1?(5pZ zHpq+xOp7@lmMsjQ(>_AEe|D!qQ?N9d`8EqoW#JgNs{+}H3XHlU(?Pp@Km6qUOu0#w zkuf*^;qAdI$WCz~Vq(dy{omz#tuQog^*-#gV*mi4{HOc1H!-v@r2YMq{&&A!RXq%g z1=*AK`g5?0mHGK2BJD+>rgjW-tLS%2xl3nGqH*%M@NnYuek&3eDrB+gm>@7Q?MIm< zFhrB=!^%ZQ5=jED?3n&rk%p0&exLl_Kpf2uyX!;j!`Obe&8^kA9HJ3WT~*4WG)iy? zV}dXd)JEUbp!Ucya1oL3gjrNQwE=} zNdqh)K7O9)sMgo3nykvf(<5Ap%O%Px=Yc`4-sX2#1`GC$D#=BO8zm#R&?X;^DALgV zvUoFMY{tSA9EjEbb>O90w_dGu&S~!z#(T(6qj9p_>DbN-3_!QYD8;V2x_))fvXHq? zEvxO|V%5~1nG$yGva{KLz4)-wk0q;3MYH?P^^`CWm7I2tlit+4t`v67`%=#Xa-IC# zz61u`iU*Qp(Hc^-VwPpOc5#dVScukbb5yNqjnH@TE1K#YQo7fg!GvnxF-< z5C`R*mlbp$d=gdEBIWj_SeG)twaV5M@;KwT|1Maf2{^NlC{Gris6$0?^C>WH={r|c zNaRkJe~{F-0EOhQ^oB)Px&-db^Y^{kZi0}(pHH9cV_HOL1}B16fcwo2f?$>*^N47T zV@Q~9_30JFktZBT+liA}`Rz4#0c+w9I|Qp@&!+EgCG*o?L37;tR~kv^?C!SxVF9rA z^FjNhL>)`q_le4+o8lEZ?r)>DRmbxT&aJmr8N&G5p&H4@E&7RUZ)cl{-Fl?C1=8lb_?h@8J7HV;1NM1^3N3P)!6w-uUXKw0Agw;}kwo4XIPcFD~bQ0#L0> z{Bq^!u=c&JevMo!ckfJ+nz^!-0chz~QbfhCnV6Z27_+utUL+~GJV0=|XRFPzGbX@A zqBiFi59noBpge^^?ihyrt9^#;ld9u<#-U=DePR1%vX;D^rgQ-g;+(CWsLC*%4+Jf9 zCENTcVLmJuPN*Sf#ML?ByqW-NosW?v3{ELmqpG|mA9}s7Ps>xW9=qJD|D0r&%^VaT z8_czrYytvW4KU%LZUJScml*M0aEwB^0|yKvWs@Q^rt4SZIE`BOTS8-8$CwKpZ~o?- z{GyVMm5|0e>aLdV{?Kb)M4Vi1oGYv>AjK~V_5ehLJDe#9n{!(U1!1+e$J2w?`ssO%+z!$#Q#c7G6|6kh#fS5ePEOy|%b-@B zRCcG@iyTIi=gQeh)?Rt4ictL6W*GJ1>T_oE8~Q)^Fs-=oW&P3 zT%Uu^b>=F03TrA4C_wR}tSg>FoG!xk*pbi`EWiC`M*QO?grp?zf&P0`wHWOu1H;bH z-rm&G_z(M7Mb&Pb8PRjSR4_%$_GD5v9Fnl+-F#KhWkVv!tl7Cukg+zkEL$7B#vo#1g6W6pKYtppB&rO93Hf0YupOeX91d~3lg~8 zQbCKJQ_Oy^>Q4K??KoLuMC6YAGahcqO;7=m0z zTZqJSuK3GSJXLHA6+qb!3YHTsSj0;^6*0Y^RKLGyW7udbU$qh0Xz8BGrfx-VGaac0 z&K+nt;D8iW7=aG&wb4C^O>8fn>zoeu@*-Cu8KZN}rgcgJyoh;!pY2&TxQ`7-vF47K zN41J2!rhHC9zeXX7~({jK=G*dibZCBaxio;q`j+g8zH2WZI}G`N`9u0=`o{NIhcab zLeVIcQcYSISA2C-xGaR#T+V|dlKvt1wJ$6E1(a;5Q@02gtmUR>3-~&iR&5?_z@bzE zHUJ2w-vO2KgE_C{0ei@+>RqZI{o@2OUOdQBW_R-33kbjM@oGUL7kSm0nxZ0q=MW_c z@A~%R+;>d&Q3(uZsQTETlFsO5$x8Jkd)hAQa49GhAza??kp)zq$_2D`supU=z@`~u zP3VQpkMsPocR|@M&+5rwq%b@ki9&l>JG~gk1uQKopbG`YS)`fPkwA9=izkMqF|vJU zJ#Ou1RJv2mtxejc;MSQGL%5GN>ZtYpOWCj=%KTACx0=>`dN6-1R_-05ndl!IiuTuQ zM}b?FXvXIA!`42v;0FL@7BprpGVlm(r#KIT$A zzM$i$eoz)$D;3#u(gY1aT;e)}E`XypS4j0}KK7F5s+$Fj>GOis^ipI#%B8Tndnw%O zC%yE>VUN#OzRZJrLI1|vGul+`^D&}q7QJy`^hgbDs9>Qhu98-Am~MCCfZCk^28(_t z6BBvmx)92J<~sE<3@UYttSSd2M1Re_70fH&+w5ehlgFxwt)4<2u?+(2^-k41SXC+h z)BzIIlA8&%F8I7brFr=y@Q1hw#)@n{vD`?%%z=ul_PGG)Cty{o+uLB7AbUub$%{P zBfh*MCqk)o^mtU8NQg9H))7Gl;>)zS?28aS24K)cQpGRs^84VL^Vt;Gj zJ%<>m?nw&KPn(5BmGX&fs^Ns(PMiwIBNsp`Q{gh1Ssi1Do6bdZsz)ve1z4iV-kt&Y zKtMZ2=!kjA-w~lhvhKhEa{vi4j_E=d_(is+!tvJ#7$HKwJz`;(GtlmeH2N1kaKc94 z10d2P5PA{;?oPbXo7zYe2c3Q(zT!-g>6IJm?){)C08Ek9+KbH3mokMfWE;m9It4Mz zl0v7=x}e23O>E2O<2>U~1h7sJZHJTj;d3v1j8K&!{wiqq9u#l1)MiV^whj0+{;td| zq};M)0^dH02r{}q?2J%}{{umg1?;3ZNmRRMpvmYb7T*`-O&<`*6%~BkU0(s*u1oJH zUcOk6L0MeH0Y7eE0?z{jmAidYkzgbuMWAxTM-a!Qsx@Nzxk}Ig2Eo9~Ccu1R!7U=r z&;BC#ZV3=s0}P=A+4^w&!RrFhkckf>b%M|lEIp142tj}!Sbd!tuT{KnoTaVL?h&@W z&`KnMbJu@2^WT_JsXYCV&|VxtYunPF;Q|?8{SseGNmy9t}k*#(GIQ^U=o| zHgjX^W^A8|1jYC+0%tHV&?5&~M`{iAAR7nj(Nonk#-1#NChWIs@?maT@~hm*AV+~n zp@!{vy$n9|RMugzGrt>&bJ*q4ky#NtS0J2}twcA5`@@rr?Uo>-M{B0mnEidgS*p)g zCz~3B6>zO`S~MLei5KI!Z&yR+Cxcp=!wopJ5X2&Nm z_Pv2{$?E#Lw~VaQ2NG_d#?wvDlKYJ?Ii~L=wvAJgOuMIUtw|Ua7gxG84RO^TrIh2j zOSZN#-a;AKb)Bd0=Y+qSIx?-yWscS-rLS-&>SRvusZTNN5gcnD=&c7`B7U;BD{0&( zOLfZKQe5mBt%w)8T^d>F1PiZn$i9-6(V$BSWkTSF>jxrxM%W{IUXKe6K0# zk*+b^a5?*Aqq5fu2nR&_x~`CVh4mElJ{bSYhztb2&QkyGD-pa0L6HE+0rVa0?5!+R zEX-+5?F}t{_n7c=hylp6@ZS&m-!Em6yinbA@Pd_yw%!FT2RU`|zLw=O*1M#Vg%w@u;DoA#R;on8ntoXhz9NzsPR3c8TYEULoP#bOU353k z7KQaC@#W=+#Ay>Yj26=xFm`)Xg5{jpEtrgYX=}awCeK2sk5i2Owne+$Z3$w6wchje zxhQlFNT8K$eRPzrVUY%BxKXp*;~$t7x>QsAv=aA)Z_yOxi`O^z-u=XX+9z5Z)%Tn4 zcd7W^8tDIM4H;W2YrFreCP|Bu{PKH(jNc1*ZtJo8Xda1_4Hi`UR~SbJ95VV|$Ex&d z`rGyWDtV_BQBK6EtDL=iU8Cy?_ldDj-<>e<4fBudaWL9CG^}CB1$5o$IZDx0zz1$G zvJZQ*(PaG(+FFDRWy}r~DslWOE3)>lI&zaPD|%6=S-E$2A(aial%<)*Y0|ua#mrL2 zK)~d~hkc^($qWS+ngtgbvC~)xNw0})db0A5(ljD!qLEdFLNsF6+LAGrsK?K5YcadI zEGLyJ-@Y^-E|;wy^nLOGGR3+SuD@8NT>AIednfz~aN=(w`ByQ0`XhDh|DTxBzIOd4 zCIK&!lU2)7w2z{$RnDk0a1ivfe68v&#gm$LP+ehcR!}4eN$2XwuaeH& zi($`Q!`G}G{g{}3B=PzSEn3ngVrpfm%kk{AF{WdecVUJH@Y{JQJ6NuZ(xx{uWN;mk zQw7qE=LAL)(O$KUf{Lm*5_2e7%UxazO!1xE>t`5RB)jt==SY5Q!mL=6b`wi)$w{DT zKuXcMb)1_5XVWe^ed5ioGMhBvltg#SGK0K$RE(T3_wcO9ta56!Eo~U-u^MWrxL|Kq zNq$qvn9@n_=puXuuPZ*lyDhNtwEFjU^yiEOs(p7D7T@EJ{}VU2bgF7|0LF`Bl**WEq*4Er#Y}+FZ z2^tjq^Z=kuw>+fgbd4-YT zk%+EPJhDroBm4(MnVN4BnK4pDlnmtVRj>REJ5^mc)>GKrS~Kqa?dS&eb=1o|DO@PB zubBENw&@T7s#r?+u0=ptHDl5UXWp|3QvQaPRi-fT@UGYCVK%HGIQEt&l2_N4@z10} z(|}}K@a28*Xj+wrTnJGCtKGSLc8Dt`I=~m+s&G}r_BuUx;fg&xd8IM~y1?Q+c1Q9y z*mI!Fm~=tOA(Az<>GIIF-0Ja3 zW=-|wR;+%EvVttBuod^QyYLei|~r`AEo44l(@3yd_wF{J zAC4SV!|siK{@1R82a@GD2@U|@YYYIu`_~_@hV1NJ%>Q^Vw3E(jx6*(zaGrkXv~g0* z#X4n{AAb@O6K&9XsgR&3E;XitSeh@0s2=l0mD@PR$n{XdIHe($f0~~xh%r&hD5c?n zxjNQ83<&=_=nVu79t4Mttw`A}jVH(tFE0SNVUl(CCsS+}X_J%yszn^=brn2k#tT(= z(*0IHVPhw&6X-T7GEpAFgo)KIluub{7}Q;Yz|37wjm5Mm;Yly5Xyb^7{Ib z%*iAJt133h`&9Xae&T)F>8tvrJhZR}n9M%An4nlXsH@WYh?|=W9^EM#Wajih?)K4V zL5Wz61Z{EC-VmxmqfJgq(?m^^L@JoQk5{G%7eWKFU16e03Q3!!0Dak+HQ|z1EYA80 z5yYWrcooB)TPBbT-GIyhIw#YGto>j0$}VEq$)K&%Z2BO9BlMLqV4^@>==f!shdecr z3`M1kh*J**LQ7|q0$M`_@%moN-S#2H2Z^_cD_RBuu838hGaI#^iQe+0cWoy9yVO@c z0A5*5e^eE4A=N4%D|Ri`8uU7=As%lVRwusdv39aX?O)*@xSn$RuGgJ=dWlM++L0Jw z;Pm79YTfH)7O$^*Q7eYYYiWFAlgXwan0WvBg^YL!XJV&6cbffa@ua`2nw1d}Sc>#8 zVwy|VT2it8Uir(nHdjUWBegHhS50uzVVmBa;)TK^ompL`W9thzWnuCcevxPCc?9Ck zyH4ONRwaIgjIeM$_*o&hT?VLN*Q*$kxQ2`>xNoDHrs@vgjKlojxR!9mL35~@u4W4D z=plYMAt7GLhqDieLLw$<5D_3GDFSMtW~ z3f$(?rc!V-jt} zC+q5j0*a4TwwrQCS1Jbu*%x`>?GZ9vF3h9`?uW%0wNpyPk}+ozmt6v+LosLedW&b*?2Qy$*YX9Cj|fZ-jYBGAL{2nS6B> zo5XfV%3(WdB;?k-Nqyg75wx4J3Z3g*AM56%F#2RMNPp6?>RyL`@R=UM@ zsnln;QxQ79u6_3aq*^uxyK3;MFidpqVBsv=O)N*SI_}hpDdsM+Dj)DH&~$GEY*Ymt z!JTTZhEEEuXRRjTg|flmrg8R0cF^<&d5V{sXivKdBM`1~k8zi6QP65i6IJje2J9@j z&}Ar8WtzH^faK8Nf#bqms78iVj7i|mrQ>;TtyOxj9m^gun$9M7IUS20l4yMOa`VT@ zYqV4U9^n8o&Nf)n_+?t(Sdtm=547{CLE2RX>qz5ogYmg@XKYL8F;#vOUBvQHDjUJQ z^GUjh?8*Ej=kwQQ-6EJx+39(8O)8{?UxN#YGtk0d!PmC7w@C23u*(98&v9Y`_2j?D z7mvZyRc;>?Ti_Xm4eB4=t)P82%813u0T0tS;~!G2q&kJ2_v(}BxzVN;(S490;9KO? z|I+jtQNF3cbc;`@ids@BjB}~M)VR}ZY4ye_bD`2Zbx3GC??W=73YWlRtoc1hFwKBQ zoyr9ki^`>9`Iydtc)V*aZRdpo2H03nB#DxQcqASgaZd~w(vE`Xt<;K9UIdPT7W3w_;18Tca=8zd5va(jro-&>i%|GITPkLQjgnCDkM* zt=}#o=6VR>Qc7Sv#IJqI*DJ8jft<+J?fkYH(JDku}P1wqC{E~s(iW+(R2+w+^- z@Ok9~s;e`#>RB@LqxK6S@#-f=2s9g2S!bVP=b3i8dz>C;JBQ6(-z+8DQhib9v5TXa z;Xcdq9mj!~A88yo;=bAj;mZ|x9gd1-#SklX=B8r0r@GF*K zIVp;5T!kS(!{>bm*)FB&G*C}CThEW+oYx^XSBlIwk|{FeLm z%Qq6p!1j;x8`*ECn_5Z`;g`B)iOf?WEp#F4DT4G(!Ygu;AvI?ikXnXJNVBdP^?r1x z$eILHJpMf`|W)fHwg#i~Tn~Cy{U-GnOMk>n#Lw74C z7*aC}u8GBzGE^xh0HkCh*2zC(Bfz4+mE(`Af5(wAX{_kx2ZH>L!$kZ$$Y9XqKcGMm z%3{ENt#_^j%$%jXgjRBgde9AW?{uQ56Aj!ER(A%nvkkxbhB zF$Qt}Il05{?D0L+(>tCN{#F&!C6gj#Xv)FYum(xnN7qLo5h6^#o*L~EhScFyX#k5lgf#@ z-)Qt1Z-;@A62=u!6s!BejR!M5&S1CbbPuzgnG=fC9;_)}Mmdg>oVB?H zN~`lScb7I_=pe#eH769V>&lWtmrqn3cm`v*IN)z6z79&8j!(p_*5~+@(%|^gXmY!W zWtj0b1;dq4L~of8p82SJuCv#82*i}fv~SL`_Z&ee>9Zg63o#O$-s?px+&4yb0@y~u zvlvo;jy9E&xAF0DC$TK)O>d_jrP1Ql2o5TY790z$t=Z}q7nVNi2974nnjg0Mmbj{g zU46O*qmM@E!QoVmu0pY>h>g|SZplw3W*+W9GE>SIGD^S~Vk>Z<$8y=!XSpSryJ|*~ z=!g`Q=t#MfiCsjh91}@#PMxlVT?^wEO%FX&kEx_f=Ni$IbuvcE-=f%?X(Q_H(8@i% zQv(a~X(e!ZVsm#vV>D>=#j3)P29?o*$=}c6)YGegM<%+eM6V4qwrIlp&4w0|bwiG; zzN$#)hk_u!*PFM{q=%e)%IGLw#DPLDt(Q|1&3UKo>5Hh1vaJ4tLPbY}cfG4&XyR#? z45xvBCaTeq8LLU+9p%a5@Pe-2H=FIp?GQB~IFBNHGcAVs_GOi74K_#%2e{nj2GAv? z)@|YWz+&W)7G1L))vrwa@iK?{k~Slb*Pq?20an#HZ_4xI(-Ty8^|!Phwza;LPH2h0 z7bT$X?4Al?afnG~)Mrr8dd}zzd|YA?A{8XrIjL)@pAGIXKa`x9B8)`Q24HTK5e!y! zb_$8)20W={%qkw42?f+jK!6*Pk#y}ZbbA2T#-BLaY~nPJEB0ux13us=yZPx_X-e`xR z@+VnwzpV<7f4(0N8}Gcoh10ID_%PbOT7?Q>NXmjD9fhF!0vH)Dae_D4T*yAMpRXrw zdZX9zrOx6TYRCODc=s#T0-Zb*h7+47tGYJ}k+7}qIl|Xn%+^gEp z$it<2u{=3(Cf1E6DxBGZr>MosW={*`OFOdB7iWT-E`*so zIo$XuB;>BoYNP_%ujdZ~=gL0b;=!RJChOvsP(DM>6?_0^TJBGSg$wWpMYT)!%cik4 zohIU%*rxfV3Jr%OVl_5DibRoY&+!j!`QXrQ+#a;XBB6qw9)mSh3l#^7_K)9wW={pa+V= zv3k$VO~lJq4@Lj}lh1Rb1u(y-bdDpS0eqLHH{!I8iy^nPi>F;v{#G9=)k*l=E^{$6 zl>uaOCcVq9%POHHDLAZSt=d^y^S!m=)gaos`!fN%ZgQF23e|b!XKmG6CxAzF&KTUy zviNo3Mb=}ty6ziVjt*L)2~r~Wr#0*W`IPp$~dh$QL!A_eTwd|&Y2H1GYYv+&W$jkDP5#0PFx#Y48?BAP@Aga-)8_<}! z3|QJ5a2Dg`Rg->myQ6sv6HOH;H&W329p8kJ`9%EU=7Cu?Bs>O6hz(jMlp$)tG9z=& zVzT=TSZ*sZt{SoEM+>rpnB=>Wj@g#;ks1EJru#r~%VI^ma%*!zg7Hy^q_uXepf+v) zK~5v-KG;{$kf|+)+ZCcXG7$kg485oUMzj7Fp}fx|B^Wcf3HRKStJ1uQzBZBLyE;yE zm6$xuUW}}?%{|q*^4bevn9a9mSQRtY2nHoIe%qaiYNNE;HnutFv^Nq4fbYcek#c+U z9YZuqB#M+JL4@JrW;WYn9mmo0eNWsv3LFE7Z?64#i8t0PwlAwQw3{=TP9zY`5AUt` z&-OLkN*m~Tj{~;+90xRdFF#h$)iXEzEe^O7*JU|PhdyvF(#9Y6gi0p4T&BisVHh1X z0c+0beaspmXfE8)+5iWDCKXJi(fpN&k1ivS;1+d3YD&=T!!WU9wygY})f1Z6oBMjB zS5sDiolgL9T3ZdKv#Sjf)itlnN)`9v?A^C33Kkg@A-Q#Qu@^bGO z*mB4n?ed4B_eJCMp>}C#>8E2c(2yx!lqI;J`i51T{aC5936bRB>#uPpN~YS7NKD*s zMzo4_U=7zuw=9E>Dy_xMICD&{?T4DYWBFpQ)t#=x?5Gx29G>?EU@y9lNI~whXh4m* z^`ef__x<$_)3%zg(&WFN_#%Fysji&Y_(tgH6JiA5ngz%A0&`7n&s7V*D@44!dz0N!6Azna4FR3?VB{MEFU9r(<>pxbCLl7;2TS9L)jO(TCEf)`_`lcbVc>F zSQ@`31}Mavp#S!W0IB%H94mFCBzu=xq&Q>@cCR0erOEobA#aP1}$oUkt|DCe-%CwZv(NoUTm*Mb_3Bt z9F?t9-bn)0W`O}@_og4Q_^JO@xP)E(EZlbY+vdPcqSZW}mKA;Xd`NX+=?*svpG#<8 z0dq_=s8l0ru;j@Q7(C##%G`%M*;fVp2wP>W4(->LNBgVS+0pq%^%2%NBLx=(r8`(7 z`|;54X{^D4<(@W-Qm)&t?T-QL^pu{S&ntB^qaIh;H90k#O^Vpn$qtNgZsPe5#Gxc-fI+of6YXzZ)N+t;@^vN|68N*-q*UvXnygdLk>I# ze}ao~lbou^MXIlg(2`_M(#LZmV6*5M0T)$T_WE33u4#(ljI>S$cg~hF%3ShwZljHn zU6_%89B4Em$~8H+(F|8wb_aOccUFl1Ys1E5SyRVQlVr2akF9V}G~)XrCeuvY)Lcaf z=Dvk16!N{;gb9l#I;rXj+*L&N{?0|jAHh-TW%zVmKt1Vn4Soox@xE|kPuoXY_^g4L z$OjwrlH}YqfN7U#wAX`pa)VX%)(Bkw!0i{d0I3C{DK?P}FYn1XnOaY>`o*o9Havo) z&O_tGD`5X(OO-ixz7t_&xao zpZu}E@J;;Uy)@yU9dC10D2VgB3TNI`2>-JRb*-)ccx(4x5x#2>AWd#qs)r7~jpzbS z_H4$KcQ?Bn!7PCFM-1kM`C@8scQy5L`BJAb{}Oy}M4F>f`}ShUrsI5yc^HA2G1`N@ z+zy7?VO+xvp%>-(c*P|Zsct;o*cRcs{)pAXA!HlaK0R>+JrN`pnoDd%(kq0c!0bIMib0`Q+?ecc_U zt|5BT?}Wso$<<%;46P>>Ke|0Ir#W1G>lgM;P{~~ZNxx0Y>xaj!KaIEs#rTi|+sy** z1ngUn43=2OUFjbJaT4U6|E0a^36I6#p2va3y`M$9MG6X9H=rn+sw)Wx1 z`CJx!t~Vz~5R4WW5boN__wd?uZm#I7@hfu+@%oeSP~nv*@4Az{@K+#oEx3QrB22x> zTLpestJnMbK10b*edh1U3;z}DZ&LkZNt=-T?Ts?nhFkUGliHPxVI+2K5%|} zJqC3}n-rWY%#AFwwG2v4_yOS26CHv3@a7@a#>UxTnY}6l28>cL1Py2YqpV`2u02L1 z_TS>7uxl5=bE96iHyV{`Ham$~PHNIW<0@gb7d&<;)0N=6zj@II1TV%o0;1?B=O(DGq z8YHE?gwn2sdaHmRKHg8EeQ$w(_H_22*<8Ed_mID92lrh&f91RUQ6u<2Sug)B5d2d@ zzkP*|SBJjmv4Cy7Y^-&eSf#DV3?USXf3)WigKfbS7M0K+RxvYO@7OD#v_BvZd3%y= zZ4VICq^~VB$tpIJLC1mNmICv9dNBhI?d$KNL7x1EgVC_MFYMOaCkAfF#z)TmG zXH~v9icX~*N0%@x!lv?3Kf}J}%$#gS+o65#p%ZX5wiwpW#~mG0=7npMgE=DCsfox5 z5`9-Nz!41TK%*1;?r@EIX{xcL>La5|@9yq+7UtWu90 zg(hWvZZ%)cA-JdwhBK zpLLpZ{Hry=9s^`_~ZgFf%j0Oqz8 zPn>o0ZDQ}~7fcngrwStjYteBkAD1L$Eemx%&vU=u#UFhEAQ1Jt>;CU^UHx>czi@>hbtCk_5g@J#$G!Cxtazq0&2ckX8v4$@y) ze(#!oCHQ+X+Rp@(WWN&pei{GD@@p#AUp#i?e>Udd60?52ieK|w{=zF!{^y_ZKUpuo zf`5&#{RPJ2_!Im~wCz`hUn59=F}QL5$?&&$(y#cxyW@YM0RSxD^LqZ_oc{{{yC3y4 z{F?VC_@7?Yujs$qwLhbC1b#yQVY2*Y<^D?WcjM+~f;FL^CGc;i&aYg5A0mI|+7bD8 duD=FM8FA3}V8?Gom?!|o?}@fYV!!?R{{XPs?7;v4 literal 0 HcmV?d00001 diff --git a/doc/软件需求模型.vsdx b/doc/软件需求模型.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..c5acba65a2947285dbe75db054a2b9e316f68fee GIT binary patch literal 22217 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 literal 0 HcmV?d00001 diff --git a/doc/软件需求规格说明书模板.docx b/doc/软件需求规格说明书模板.docx new file mode 100644 index 0000000000000000000000000000000000000000..5b486cfd39ebdfa12e75caa0f312582d25a27b7d GIT binary patch literal 20020 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 un7G%Gh1w0 Date: Thu, 15 May 2025 14:52:34 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B4=A8=E9=87=8F?= =?UTF-8?q?=E5=88=86=E6=9E=90=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/开源代码质量分析报告模板.docx | Bin 21511 -> 15686 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/开源代码质量分析报告模板.docx b/doc/开源代码质量分析报告模板.docx index 626edee6bb8b8a9a5b587ee52f726c15ca9517fc..110331ccf9157f70f143812eaf7b4c10d1d9b14b 100644 GIT binary patch literal 15686 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 ZQ=26#0rGPt3xN9mr}oa;Jj>5d{~t1L!!!T@ literal 21511 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 WH!E=91GJA&lp!6sTcyhn!~+1MwC$S! From 2a1944a9aa5ad56b535602f2c8492e7cc7c32cbd Mon Sep 17 00:00:00 2001 From: Wang-YYu-Lu <1756892659@qq.com> Date: Thu, 15 May 2025 23:21:33 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E5=AE=8C=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Notes-master/res/values/styles.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Notes-master/res/values/styles.xml b/src/Notes-master/res/values/styles.xml index d750e65..c6e2581 100644 --- a/src/Notes-master/res/values/styles.xml +++ b/src/Notes-master/res/values/styles.xml @@ -63,7 +63,7 @@ \ No newline at end of file From 779540e963b8f9f35f02ae5d72e03cbf0178370f Mon Sep 17 00:00:00 2001 From: Wang-YYu-Lu <1756892659@qq.com> Date: Tue, 27 May 2025 09:24:58 +0800 Subject: [PATCH 07/11] =?UTF-8?q?data=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/net/micode/notes/data/Contact.java | 31 +- .../src/net/micode/notes/data/Notes.java | 219 ++++++----- .../notes/data/NotesDatabaseHelper.java | 365 +++++++++++------- .../net/micode/notes/data/NotesProvider.java | 236 ++++++----- 4 files changed, 506 insertions(+), 345 deletions(-) diff --git a/src/Notes-master/src/net/micode/notes/data/Contact.java b/src/Notes-master/src/net/micode/notes/data/Contact.java index d97ac5d..c5fa8b4 100644 --- a/src/Notes-master/src/net/micode/notes/data/Contact.java +++ b/src/Notes-master/src/net/micode/notes/data/Contact.java @@ -14,8 +14,10 @@ * limitations under the License. */ +// 定义联系人相关操作的类,位于小米便签的数据模块 package net.micode.notes.data; +// 导入所需的Android和Java库 import android.content.Context; import android.database.Cursor; import android.provider.ContactsContract.CommonDataKinds.Phone; @@ -25,28 +27,45 @@ import android.util.Log; import java.util.HashMap; +// 联系人工具类,用于通过电话号码获取联系人信息 public class Contact { + // 缓存联系人信息的HashMap,提高查询效率 private static HashMap sContactCache; + + // 日志标签 private static final String TAG = "Contact"; + // 查询联系人信息的SQL选择语句模板 + // 用于匹配电话号码和获取联系人姓名 private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER - + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" - + " AND " + Data.RAW_CONTACT_ID + " IN " + + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + + " AND " + Data.RAW_CONTACT_ID + " IN " + "(SELECT raw_contact_id " + " FROM phone_lookup" + " WHERE min_match = '+')"; + /** + * 根据电话号码获取联系人姓名 + * @param context Android上下文对象 + * @param phoneNumber 要查询的电话号码 + * @return 联系人姓名,如果找不到则返回null + */ public static String getContact(Context context, String phoneNumber) { + // 如果缓存未初始化,则初始化缓存 if(sContactCache == null) { sContactCache = new HashMap(); } + // 先检查缓存中是否已有该号码对应的联系人 if(sContactCache.containsKey(phoneNumber)) { return sContactCache.get(phoneNumber); } + // 准备查询语句,替换最小匹配参数 String selection = CALLER_ID_SELECTION.replace("+", PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); + + // 查询联系人数据库 Cursor cursor = context.getContentResolver().query( Data.CONTENT_URI, new String [] { Phone.DISPLAY_NAME }, @@ -54,20 +73,26 @@ public class Contact { new String[] { phoneNumber }, null); + // 处理查询结果 if (cursor != null && cursor.moveToFirst()) { try { + // 获取联系人姓名 String name = cursor.getString(0); + // 将结果存入缓存 sContactCache.put(phoneNumber, name); return name; } catch (IndexOutOfBoundsException e) { + // 处理数据越界异常 Log.e(TAG, " Cursor get string error " + e.toString()); return null; } finally { + // 确保关闭Cursor释放资源 cursor.close(); } } else { + // 没有找到匹配的联系人 Log.d(TAG, "No contact matched with number:" + phoneNumber); return null; } } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/data/Notes.java b/src/Notes-master/src/net/micode/notes/data/Notes.java index f240604..f5bbec0 100644 --- a/src/Notes-master/src/net/micode/notes/data/Notes.java +++ b/src/Notes-master/src/net/micode/notes/data/Notes.java @@ -14,266 +14,277 @@ * limitations under the License. */ +// 定义便签应用的核心常量、URI和数据结构 package net.micode.notes.data; +// 导入Android Uri类 import android.net.Uri; + +// 便签应用的核心常量类,包含数据类型、URI和列定义 public class Notes { + // ContentProvider的授权标识符 public static final String AUTHORITY = "micode_notes"; + + // 日志标签 public static final String TAG = "Notes"; - public static final int TYPE_NOTE = 0; - public static final int TYPE_FOLDER = 1; - public static final int TYPE_SYSTEM = 2; + + // 便签类型常量 + public static final int TYPE_NOTE = 0; // 普通便签类型 + public static final int TYPE_FOLDER = 1; // 文件夹类型 + public static final int TYPE_SYSTEM = 2; // 系统文件夹类型 /** - * Following IDs are system folders' identifiers - * {@link Notes#ID_ROOT_FOLDER } is default folder - * {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder - * {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records + * 系统文件夹的标识符常量 + * {@link Notes#ID_ROOT_FOLDER } 是默认根文件夹 + * {@link Notes#ID_TEMPARAY_FOLDER } 用于存放无文件夹的便签 + * {@link Notes#ID_CALL_RECORD_FOLDER} 用于存储通话记录 */ - public static final int ID_ROOT_FOLDER = 0; - public static final int ID_TEMPARAY_FOLDER = -1; - public static final int ID_CALL_RECORD_FOLDER = -2; - public static final int ID_TRASH_FOLER = -3; - - public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; - public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; - public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; - public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; - public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; - public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; - - public static final int TYPE_WIDGET_INVALIDE = -1; - public static final int TYPE_WIDGET_2X = 0; - public static final int TYPE_WIDGET_4X = 1; - + public static final int ID_ROOT_FOLDER = 0; // 根文件夹ID + public static final int ID_TEMPARAY_FOLDER = -1; // 临时文件夹ID + public static final int ID_CALL_RECORD_FOLDER = -2; // 通话记录文件夹ID + public static final int ID_TRASH_FOLER = -3; // 回收站文件夹ID + + // Intent附加数据键名常量 + public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; // 提醒日期 + public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; // 背景色ID + public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; // 小部件ID + public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; // 小部件类型 + public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; // 文件夹ID + public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; // 通话日期 + + // 小部件类型常量 + public static final int TYPE_WIDGET_INVALIDE = -1; // 无效小部件类型 + public static final int TYPE_WIDGET_2X = 0; // 2x大小的小部件 + public static final int TYPE_WIDGET_4X = 1; // 4x大小的小部件 + + // 数据类型的常量定义 public static class DataConstants { - public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; - public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; + public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; // 文本便签类型 + public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; // 通话记录便签类型 } /** - * Uri to query all notes and folders + * 查询所有便签和文件夹的URI */ public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); /** - * Uri to query data + * 查询便签数据的URI */ public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); + // 便签表的列定义接口 public interface NoteColumns { /** - * The unique ID for a row - *

Type: INTEGER (long)

+ * 行的唯一ID + *

类型: INTEGER (long)

*/ public static final String ID = "_id"; /** - * The parent's id for note or folder - *

Type: INTEGER (long)

+ * 便签或文件夹的父ID + *

类型: INTEGER (long)

*/ public static final String PARENT_ID = "parent_id"; /** - * Created data for note or folder - *

Type: INTEGER (long)

+ * 便签或文件夹的创建日期 + *

类型: INTEGER (long)

*/ public static final String CREATED_DATE = "created_date"; /** - * Latest modified date - *

Type: INTEGER (long)

+ * 最后修改日期 + *

类型: INTEGER (long)

*/ public static final String MODIFIED_DATE = "modified_date"; - /** - * Alert date - *

Type: INTEGER (long)

+ * 提醒日期 + *

类型: INTEGER (long)

*/ public static final String ALERTED_DATE = "alert_date"; /** - * Folder's name or text content of note - *

Type: TEXT

+ * 文件夹名称或便签的文本内容摘要 + *

类型: TEXT

*/ public static final String SNIPPET = "snippet"; /** - * Note's widget id - *

Type: INTEGER (long)

+ * 便签关联的小部件ID + *

类型: INTEGER (long)

*/ public static final String WIDGET_ID = "widget_id"; /** - * Note's widget type - *

Type: INTEGER (long)

+ * 便签关联的小部件类型 + *

类型: INTEGER (long)

*/ public static final String WIDGET_TYPE = "widget_type"; /** - * Note's background color's id - *

Type: INTEGER (long)

+ * 便签背景颜色的ID + *

类型: INTEGER (long)

*/ public static final String BG_COLOR_ID = "bg_color_id"; /** - * For text note, it doesn't has attachment, for multi-media - * note, it has at least one attachment - *

Type: INTEGER

+ * 是否有附件:文本便签没有附件,多媒体便签至少有一个附件 + *

类型: INTEGER

*/ public static final String HAS_ATTACHMENT = "has_attachment"; /** - * Folder's count of notes - *

Type: INTEGER (long)

+ * 文件夹中的便签数量 + *

类型: INTEGER (long)

*/ public static final String NOTES_COUNT = "notes_count"; /** - * The file type: folder or note - *

Type: INTEGER

+ * 文件类型:文件夹或便签 + *

类型: INTEGER

*/ public static final String TYPE = "type"; /** - * The last sync id - *

Type: INTEGER (long)

+ * 最后同步ID + *

类型: INTEGER (long)

*/ public static final String SYNC_ID = "sync_id"; /** - * Sign to indicate local modified or not - *

Type: INTEGER

+ * 本地修改标志 + *

类型: INTEGER

*/ public static final String LOCAL_MODIFIED = "local_modified"; /** - * Original parent id before moving into temporary folder - *

Type : INTEGER

+ * 移动到临时文件夹前的原始父ID + *

类型 : INTEGER

*/ public static final String ORIGIN_PARENT_ID = "origin_parent_id"; /** - * The gtask id - *

Type : TEXT

+ * Google Task ID + *

类型 : TEXT

*/ public static final String GTASK_ID = "gtask_id"; /** - * The version code - *

Type : INTEGER (long)

+ * 版本号 + *

类型 : INTEGER (long)

*/ public static final String VERSION = "version"; } + // 数据表的列定义接口 public interface DataColumns { /** - * The unique ID for a row - *

Type: INTEGER (long)

+ * 行的唯一ID + *

类型: INTEGER (long)

*/ public static final String ID = "_id"; /** - * The MIME type of the item represented by this row. - *

Type: Text

+ * 该行数据项的MIME类型 + *

类型: Text

*/ public static final String MIME_TYPE = "mime_type"; /** - * The reference id to note that this data belongs to - *

Type: INTEGER (long)

+ * 该数据所属便签的引用ID + *

类型: INTEGER (long)

*/ public static final String NOTE_ID = "note_id"; /** - * Created data for note or folder - *

Type: INTEGER (long)

+ * 数据项的创建日期 + *

类型: INTEGER (long)

*/ public static final String CREATED_DATE = "created_date"; /** - * Latest modified date - *

Type: INTEGER (long)

+ * 最后修改日期 + *

类型: INTEGER (long)

*/ public static final String MODIFIED_DATE = "modified_date"; /** - * Data's content - *

Type: TEXT

+ * 数据内容 + *

类型: TEXT

*/ public static final String CONTENT = "content"; - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * integer data type - *

Type: INTEGER

+ * 通用数据列1,具体含义由{@link #MIMETYPE}决定,用于整数类型 + *

类型: INTEGER

*/ public static final String DATA1 = "data1"; /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * integer data type - *

Type: INTEGER

+ * 通用数据列2,具体含义由{@link #MIMETYPE}决定,用于整数类型 + *

类型: INTEGER

*/ public static final String DATA2 = "data2"; /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

+ * 通用数据列3,具体含义由{@link #MIMETYPE}决定,用于文本类型 + *

类型: TEXT

*/ public static final String DATA3 = "data3"; /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

+ * 通用数据列4,具体含义由{@link #MIMETYPE}决定,用于文本类型 + *

类型: TEXT

*/ public static final String DATA4 = "data4"; /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

+ * 通用数据列5,具体含义由{@link #MIMETYPE}决定,用于文本类型 + *

类型: TEXT

*/ public static final String DATA5 = "data5"; } + // 文本便签的数据列定义 public static final class TextNote implements DataColumns { /** - * Mode to indicate the text in check list mode or not - *

Type: Integer 1:check list mode 0: normal mode

+ * 模式标志:是否为清单模式 + *

类型: Integer 1:清单模式 0:普通模式

*/ public static final String MODE = DATA1; + // 清单模式常量 public static final int MODE_CHECK_LIST = 1; - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; - - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; + // 文本便签的MIME类型 + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; // 多项目类型 + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; // 单项目类型 + // 文本便签的URI public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); } + // 通话记录便签的数据列定义 public static final class CallNote implements DataColumns { /** - * Call date for this record - *

Type: INTEGER (long)

+ * 通话记录日期 + *

类型: INTEGER (long)

*/ public static final String CALL_DATE = DATA1; /** - * Phone number for this record - *

Type: TEXT

+ * 电话号码 + *

类型: TEXT

*/ public static final String PHONE_NUMBER = DATA3; - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; - - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; + // 通话记录便签的MIME类型 + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; // 多项目类型 + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; // 单项目类型 + // 通话记录便签的URI public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java b/src/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java index ffe5d57..70b6bb4 100644 --- a/src/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java +++ b/src/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java @@ -14,210 +14,230 @@ * limitations under the License. */ +// 数据库帮助类,负责创建和维护便签应用的数据库 package net.micode.notes.data; +// 导入所需的Android类 import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; +// 导入便签数据相关的常量定义 import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.NoteColumns; - +// 数据库帮助类,继承自SQLiteOpenHelper public class NotesDatabaseHelper extends SQLiteOpenHelper { + // 数据库名称常量 private static final String DB_NAME = "note.db"; + // 当前数据库版本号 private static final int DB_VERSION = 4; + // 数据库表名定义接口 public interface TABLE { - public static final String NOTE = "note"; - - public static final String DATA = "data"; + public static final String NOTE = "note"; // 便签表名 + public static final String DATA = "data"; // 数据表名 } + // 日志标签 private static final String TAG = "NotesDatabaseHelper"; + // 单例实例 private static NotesDatabaseHelper mInstance; + // 创建便签表的SQL语句 private static final String CREATE_NOTE_TABLE_SQL = - "CREATE TABLE " + TABLE.NOTE + "(" + - NoteColumns.ID + " INTEGER PRIMARY KEY," + - NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + - NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + - ")"; - + "CREATE TABLE " + TABLE.NOTE + "(" + + NoteColumns.ID + " INTEGER PRIMARY KEY," + // 主键ID + NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 父ID,默认为0 + NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + // 提醒日期 + NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + // 背景颜色ID + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建日期 + NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + // 是否有附件 + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改日期 + NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + // 便签数量 + NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + // 内容摘要 + NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + // 类型 + NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + // 小部件ID + NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + // 小部件类型 + NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + // 同步ID + NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + // 本地修改标志 + NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 原始父ID + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + // Google任务ID + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + // 版本号 + ")"; + + // 创建数据表的SQL语句 private static final String CREATE_DATA_TABLE_SQL = - "CREATE TABLE " + TABLE.DATA + "(" + - DataColumns.ID + " INTEGER PRIMARY KEY," + - DataColumns.MIME_TYPE + " TEXT NOT NULL," + - DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA1 + " INTEGER," + - DataColumns.DATA2 + " INTEGER," + - DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + - ")"; - + "CREATE TABLE " + TABLE.DATA + "(" + + DataColumns.ID + " INTEGER PRIMARY KEY," + // 主键ID + DataColumns.MIME_TYPE + " TEXT NOT NULL," + // MIME类型 + DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + // 关联的便签ID + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建日期 + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改日期 + DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + // 内容 + DataColumns.DATA1 + " INTEGER," + // 通用数据列1 + DataColumns.DATA2 + " INTEGER," + // 通用数据列2 + DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + // 通用数据列3 + DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + // 通用数据列4 + DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + // 通用数据列5 + ")"; + + // 创建数据表note_id索引的SQL语句 private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = - "CREATE INDEX IF NOT EXISTS note_id_index ON " + - TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; + "CREATE INDEX IF NOT EXISTS note_id_index ON " + + TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; /** - * Increase folder's note count when move note to the folder + * 触发器:当更新便签的父ID时,增加目标文件夹的便签计数 */ private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER increase_folder_count_on_update "+ - " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; + "CREATE TRIGGER increase_folder_count_on_update "+ + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + + " END"; /** - * Decrease folder's note count when move note from folder + * 触发器:当更新便签的父ID时,减少原文件夹的便签计数 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER decrease_folder_count_on_update " + - " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + - " END"; + "CREATE TRIGGER decrease_folder_count_on_update " + + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + + " END"; /** - * Increase folder's note count when insert new note to the folder + * 触发器:当插入新便签时,增加父文件夹的便签计数 */ private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = - "CREATE TRIGGER increase_folder_count_on_insert " + - " AFTER INSERT ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + - " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; + "CREATE TRIGGER increase_folder_count_on_insert " + + " AFTER INSERT ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + + " END"; /** - * Decrease folder's note count when delete note from the folder + * 触发器:当删除便签时,减少父文件夹的便签计数 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = - "CREATE TRIGGER decrease_folder_count_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN " + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + - " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + - " AND " + NoteColumns.NOTES_COUNT + ">0;" + - " END"; + "CREATE TRIGGER decrease_folder_count_on_delete " + + " AFTER DELETE ON " + TABLE.NOTE + + " BEGIN " + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + + " AND " + NoteColumns.NOTES_COUNT + ">0;" + + " END"; /** - * Update note's content when insert data with type {@link DataConstants#NOTE} + * 触发器:当插入类型为NOTE的数据时,更新便签的内容摘要 */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = - "CREATE TRIGGER update_note_content_on_insert " + - " AFTER INSERT ON " + TABLE.DATA + - " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; + "CREATE TRIGGER update_note_content_on_insert " + + " AFTER INSERT ON " + TABLE.DATA + + " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + + " BEGIN" + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + + " END"; /** - * Update note's content when data with {@link DataConstants#NOTE} type has changed + * 触发器:当更新类型为NOTE的数据时,更新便签的内容摘要 */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = - "CREATE TRIGGER update_note_content_on_update " + - " AFTER UPDATE ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + - " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; + "CREATE TRIGGER update_note_content_on_update " + + " AFTER UPDATE ON " + TABLE.DATA + + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + + " BEGIN" + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + + " END"; /** - * Update note's content when data with {@link DataConstants#NOTE} type has deleted + * 触发器:当删除类型为NOTE的数据时,清空便签的内容摘要 */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = - "CREATE TRIGGER update_note_content_on_delete " + - " AFTER delete ON " + TABLE.DATA + - " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.SNIPPET + "=''" + - " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + - " END"; + "CREATE TRIGGER update_note_content_on_delete " + + " AFTER delete ON " + TABLE.DATA + + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + + " BEGIN" + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.SNIPPET + "=''" + + " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + + " END"; /** - * Delete datas belong to note which has been deleted + * 触发器:当删除便签时,自动删除关联的数据 */ private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = - "CREATE TRIGGER delete_data_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN" + - " DELETE FROM " + TABLE.DATA + - " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + - " END"; + "CREATE TRIGGER delete_data_on_delete " + + " AFTER DELETE ON " + TABLE.NOTE + + " BEGIN" + + " DELETE FROM " + TABLE.DATA + + " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + + " END"; /** - * Delete notes belong to folder which has been deleted + * 触发器:当删除文件夹时,自动删除该文件夹下的所有便签 */ private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = - "CREATE TRIGGER folder_delete_notes_on_delete " + - " AFTER DELETE ON " + TABLE.NOTE + - " BEGIN" + - " DELETE FROM " + TABLE.NOTE + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; + "CREATE TRIGGER folder_delete_notes_on_delete " + + " AFTER DELETE ON " + TABLE.NOTE + + " BEGIN" + + " DELETE FROM " + TABLE.NOTE + + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + + " END"; /** - * Move notes belong to folder which has been moved to trash folder + * 触发器:当文件夹被移动到回收站时,将其下的便签也移动到回收站 */ private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = - "CREATE TRIGGER folder_move_notes_on_trash " + - " AFTER UPDATE ON " + TABLE.NOTE + - " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + - " BEGIN" + - " UPDATE " + TABLE.NOTE + - " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + - " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; - + "CREATE TRIGGER folder_move_notes_on_trash " + + " AFTER UPDATE ON " + TABLE.NOTE + + " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + + " BEGIN" + + " UPDATE " + TABLE.NOTE + + " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + + " END"; + + // 构造函数 public NotesDatabaseHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } + /** + * 创建便签表 + * @param db SQLiteDatabase对象 + */ public void createNoteTable(SQLiteDatabase db) { - db.execSQL(CREATE_NOTE_TABLE_SQL); - reCreateNoteTableTriggers(db); - createSystemFolder(db); + db.execSQL(CREATE_NOTE_TABLE_SQL); // 执行创建表SQL + reCreateNoteTableTriggers(db); // 重建触发器 + createSystemFolder(db); // 创建系统文件夹 Log.d(TAG, "note table has been created"); } + /** + * 重建便签表相关的触发器 + * @param db SQLiteDatabase对象 + */ private void reCreateNoteTableTriggers(SQLiteDatabase db) { + // 删除所有现有的触发器 db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); @@ -226,6 +246,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); + // 重新创建所有触发器 db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER); @@ -235,18 +256,22 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); } + /** + * 创建系统文件夹 + * @param db SQLiteDatabase对象 + */ private void createSystemFolder(SQLiteDatabase db) { ContentValues values = new ContentValues(); /** - * call record foler for call notes + * 创建通话记录文件夹 */ values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); db.insert(TABLE.NOTE, null, values); /** - * root folder which is default folder + * 创建根文件夹 */ values.clear(); values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); @@ -254,7 +279,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.insert(TABLE.NOTE, null, values); /** - * temporary folder which is used for moving note + * 创建临时文件夹(用于移动便签时临时存放) */ values.clear(); values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); @@ -262,7 +287,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.insert(TABLE.NOTE, null, values); /** - * create trash folder + * 创建回收站文件夹 */ values.clear(); values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); @@ -270,23 +295,38 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.insert(TABLE.NOTE, null, values); } + /** + * 创建数据表 + * @param db SQLiteDatabase对象 + */ public void createDataTable(SQLiteDatabase db) { - db.execSQL(CREATE_DATA_TABLE_SQL); - reCreateDataTableTriggers(db); - db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); + db.execSQL(CREATE_DATA_TABLE_SQL); // 执行创建表SQL + reCreateDataTableTriggers(db); // 重建触发器 + db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); // 创建索引 Log.d(TAG, "data table has been created"); } + /** + * 重建数据表相关的触发器 + * @param db SQLiteDatabase对象 + */ private void reCreateDataTableTriggers(SQLiteDatabase db) { + // 删除所有现有的触发器 db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); + // 重新创建所有触发器 db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); } + /** + * 获取单例实例 + * @param context 上下文对象 + * @return NotesDatabaseHelper实例 + */ static synchronized NotesDatabaseHelper getInstance(Context context) { if (mInstance == null) { mInstance = new NotesDatabaseHelper(context); @@ -294,69 +334,98 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { return mInstance; } + /** + * 创建数据库时调用 + * @param db SQLiteDatabase对象 + */ @Override public void onCreate(SQLiteDatabase db) { - createNoteTable(db); - createDataTable(db); + createNoteTable(db); // 创建便签表 + createDataTable(db); // 创建数据表 } + /** + * 升级数据库时调用 + * @param db SQLiteDatabase对象 + * @param oldVersion 旧版本号 + * @param newVersion 新版本号 + */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - boolean reCreateTriggers = false; - boolean skipV2 = false; + boolean reCreateTriggers = false; // 是否需要重建触发器 + boolean skipV2 = false; // 是否跳过V2升级 + // 从V1升级到V2 if (oldVersion == 1) { upgradeToV2(db); - skipV2 = true; // this upgrade including the upgrade from v2 to v3 + skipV2 = true; // 这个升级包含从V2到V3的升级 oldVersion++; } + // 从V2升级到V3 if (oldVersion == 2 && !skipV2) { upgradeToV3(db); reCreateTriggers = true; oldVersion++; } + // 从V3升级到V4 if (oldVersion == 3) { upgradeToV4(db); oldVersion++; } + // 如果需要,重建触发器 if (reCreateTriggers) { reCreateNoteTableTriggers(db); reCreateDataTableTriggers(db); } + // 检查版本号是否匹配 if (oldVersion != newVersion) { throw new IllegalStateException("Upgrade notes database to version " + newVersion + "fails"); } } + /** + * 升级到V2版本:重建所有表 + * @param db SQLiteDatabase对象 + */ private void upgradeToV2(SQLiteDatabase db) { - db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); - db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); - createNoteTable(db); - createDataTable(db); + db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); // 删除便签表 + db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); // 删除数据表 + createNoteTable(db); // 重新创建便签表 + createDataTable(db); // 重新创建数据表 } + /** + * 升级到V3版本:添加GTASK_ID列和回收站文件夹 + * @param db SQLiteDatabase对象 + */ private void upgradeToV3(SQLiteDatabase db) { - // drop unused triggers + // 删除不再使用的触发器 db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete"); db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update"); - // add a column for gtask id + + // 添加GTASK_ID列 db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''"); - // add a trash system folder + + // 添加回收站系统文件夹 ContentValues values = new ContentValues(); values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); db.insert(TABLE.NOTE, null, values); } + /** + * 升级到V4版本:添加VERSION列 + * @param db SQLiteDatabase对象 + */ private void upgradeToV4(SQLiteDatabase db) { db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0"); } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/data/NotesProvider.java b/src/Notes-master/src/net/micode/notes/data/NotesProvider.java index edb0a60..f68161d 100644 --- a/src/Notes-master/src/net/micode/notes/data/NotesProvider.java +++ b/src/Notes-master/src/net/micode/notes/data/NotesProvider.java @@ -14,9 +14,10 @@ * limitations under the License. */ +// 便签内容提供者,负责处理便签数据的CRUD操作 package net.micode.notes.data; - +// 导入所需的Android类 import android.app.SearchManager; import android.content.ContentProvider; import android.content.ContentUris; @@ -29,174 +30,206 @@ import android.net.Uri; import android.text.TextUtils; import android.util.Log; +// 导入应用资源和数据定义 import net.micode.notes.R; import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.NotesDatabaseHelper.TABLE; - +// 便签内容提供者类,继承自ContentProvider public class NotesProvider extends ContentProvider { + // URI匹配器,用于匹配不同的URI请求 private static final UriMatcher mMatcher; + // 数据库帮助类实例 private NotesDatabaseHelper mHelper; + // 日志标签 private static final String TAG = "NotesProvider"; - private static final int URI_NOTE = 1; - private static final int URI_NOTE_ITEM = 2; - private static final int URI_DATA = 3; - private static final int URI_DATA_ITEM = 4; - - private static final int URI_SEARCH = 5; - private static final int URI_SEARCH_SUGGEST = 6; + // URI匹配常量定义 + private static final int URI_NOTE = 1; // 便签表URI + private static final int URI_NOTE_ITEM = 2; // 单个便签URI + private static final int URI_DATA = 3; // 数据表URI + private static final int URI_DATA_ITEM = 4; // 单个数据项URI + private static final int URI_SEARCH = 5; // 搜索URI + private static final int URI_SEARCH_SUGGEST = 6; // 搜索建议URI + // 静态初始化块,配置URI匹配器 static { mMatcher = new UriMatcher(UriMatcher.NO_MATCH); - mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); - mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); - mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); - mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); - mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); - mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); - mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); + mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); // 匹配便签表 + mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); // 匹配单个便签 + mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); // 匹配数据表 + mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); // 匹配单个数据项 + mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); // 匹配搜索 + mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); // 匹配搜索建议 + mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); // 带参数的搜索建议 } /** - * x'0A' represents the '\n' character in sqlite. For title and content in the search result, - * we will trim '\n' and white space in order to show more information. + * 搜索投影字段定义: + * x'0A'在SQLite中代表换行符'\n'。对于搜索结果中的标题和内容, + * 我们将去除'\n'和空格以显示更多信息。 */ - private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," - + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," - + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," - + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," - + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," - + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," - + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," // 便签ID + + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," // 建议项额外数据 + + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," // 建议文本1 + + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," // 建议文本2 + + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," // 建议图标 + + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," // 建议动作 + + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; // 建议数据 + // 便签片段搜索查询SQL private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION - + " FROM " + TABLE.NOTE - + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" - + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER - + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + + " FROM " + TABLE.NOTE // 从便签表查询 + + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" // 按片段匹配 + + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER // 排除回收站中的便签 + + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; // 只查询普通便签类型 + /** + * 创建内容提供者时调用 + * @return 是否成功创建 + */ @Override public boolean onCreate() { - mHelper = NotesDatabaseHelper.getInstance(getContext()); + mHelper = NotesDatabaseHelper.getInstance(getContext()); // 获取数据库帮助类实例 return true; } + /** + * 查询方法 + * @param uri 请求的URI + * @param projection 要返回的列 + * @param selection 选择条件 + * @param selectionArgs 选择参数 + * @param sortOrder 排序方式 + * @return 查询结果的Cursor + */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { + String sortOrder) { Cursor c = null; - SQLiteDatabase db = mHelper.getReadableDatabase(); + SQLiteDatabase db = mHelper.getReadableDatabase(); // 获取可读数据库 String id = null; - switch (mMatcher.match(uri)) { - case URI_NOTE: + switch (mMatcher.match(uri)) { // 根据URI匹配不同操作 + case URI_NOTE: // 查询便签表 c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, sortOrder); break; - case URI_NOTE_ITEM: + case URI_NOTE_ITEM: // 查询单个便签 id = uri.getPathSegments().get(1); c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder); break; - case URI_DATA: + case URI_DATA: // 查询数据表 c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, sortOrder); break; - case URI_DATA_ITEM: + case URI_DATA_ITEM: // 查询单个数据项 id = uri.getPathSegments().get(1); c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder); break; - case URI_SEARCH: - case URI_SEARCH_SUGGEST: + case URI_SEARCH: // 搜索请求 + case URI_SEARCH_SUGGEST: // 搜索建议请求 if (sortOrder != null || projection != null) { throw new IllegalArgumentException( "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); } String searchString = null; - if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { + if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { // 处理搜索建议请求 if (uri.getPathSegments().size() > 1) { searchString = uri.getPathSegments().get(1); } - } else { + } else { // 处理普通搜索请求 searchString = uri.getQueryParameter("pattern"); } - if (TextUtils.isEmpty(searchString)) { + if (TextUtils.isEmpty(searchString)) { // 搜索字符串为空则返回null return null; } try { - searchString = String.format("%%%s%%", searchString); - c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, + searchString = String.format("%%%s%%", searchString); // 格式化搜索字符串 + c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, // 执行原始查询 new String[] { searchString }); } catch (IllegalStateException ex) { - Log.e(TAG, "got exception: " + ex.toString()); + Log.e(TAG, "got exception: " + ex.toString()); // 记录异常 } break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); // 未知URI抛出异常 } if (c != null) { - c.setNotificationUri(getContext().getContentResolver(), uri); + c.setNotificationUri(getContext().getContentResolver(), uri); // 设置通知URI } return c; } + /** + * 插入方法 + * @param uri 请求的URI + * @param values 要插入的值 + * @return 新插入项的URI + */ @Override public Uri insert(Uri uri, ContentValues values) { - SQLiteDatabase db = mHelper.getWritableDatabase(); + SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写数据库 long dataId = 0, noteId = 0, insertedId = 0; - switch (mMatcher.match(uri)) { - case URI_NOTE: + switch (mMatcher.match(uri)) { // 根据URI匹配不同操作 + case URI_NOTE: // 插入便签 insertedId = noteId = db.insert(TABLE.NOTE, null, values); break; - case URI_DATA: - if (values.containsKey(DataColumns.NOTE_ID)) { + case URI_DATA: // 插入数据 + if (values.containsKey(DataColumns.NOTE_ID)) { // 检查是否包含便签ID noteId = values.getAsLong(DataColumns.NOTE_ID); } else { - Log.d(TAG, "Wrong data format without note id:" + values.toString()); + Log.d(TAG, "Wrong data format without note id:" + values.toString()); // 记录格式错误 } insertedId = dataId = db.insert(TABLE.DATA, null, values); break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); // 未知URI抛出异常 } - // Notify the note uri + // 通知便签URI变化 if (noteId > 0) { getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); } - // Notify the data uri + // 通知数据URI变化 if (dataId > 0) { getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); } - return ContentUris.withAppendedId(uri, insertedId); + return ContentUris.withAppendedId(uri, insertedId); // 返回新插入项的URI } + /** + * 删除方法 + * @param uri 请求的URI + * @param selection 选择条件 + * @param selectionArgs 选择参数 + * @return 删除的行数 + */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); + SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写数据库 boolean deleteData = false; - switch (mMatcher.match(uri)) { - case URI_NOTE: - selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; + switch (mMatcher.match(uri)) { // 根据URI匹配不同操作 + case URI_NOTE: // 删除便签 + selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; // 只允许删除ID大于0的便签 count = db.delete(TABLE.NOTE, selection, selectionArgs); break; - case URI_NOTE_ITEM: + case URI_NOTE_ITEM: // 删除单个便签 id = uri.getPathSegments().get(1); /** - * ID that smaller than 0 is system folder which is not allowed to - * trash + * ID小于0的是系统文件夹,不允许删除 */ long noteId = Long.valueOf(id); if (noteId <= 0) { @@ -205,101 +238,124 @@ public class NotesProvider extends ContentProvider { count = db.delete(TABLE.NOTE, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); break; - case URI_DATA: + case URI_DATA: // 删除数据 count = db.delete(TABLE.DATA, selection, selectionArgs); deleteData = true; break; - case URI_DATA_ITEM: + case URI_DATA_ITEM: // 删除单个数据项 id = uri.getPathSegments().get(1); count = db.delete(TABLE.DATA, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); deleteData = true; break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); // 未知URI抛出异常 } - if (count > 0) { + if (count > 0) { // 如果删除了数据 if (deleteData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); // 通知便签URI变化 } - getContext().getContentResolver().notifyChange(uri, null); + getContext().getContentResolver().notifyChange(uri, null); // 通知当前URI变化 } return count; } + /** + * 更新方法 + * @param uri 请求的URI + * @param values 要更新的值 + * @param selection 选择条件 + * @param selectionArgs 选择参数 + * @return 更新的行数 + */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); + SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写数据库 boolean updateData = false; - switch (mMatcher.match(uri)) { - case URI_NOTE: - increaseNoteVersion(-1, selection, selectionArgs); + switch (mMatcher.match(uri)) { // 根据URI匹配不同操作 + case URI_NOTE: // 更新便签 + increaseNoteVersion(-1, selection, selectionArgs); // 增加便签版本 count = db.update(TABLE.NOTE, values, selection, selectionArgs); break; - case URI_NOTE_ITEM: + case URI_NOTE_ITEM: // 更新单个便签 id = uri.getPathSegments().get(1); - increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); + increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); // 增加便签版本 count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); break; - case URI_DATA: + case URI_DATA: // 更新数据 count = db.update(TABLE.DATA, values, selection, selectionArgs); updateData = true; break; - case URI_DATA_ITEM: + case URI_DATA_ITEM: // 更新单个数据项 id = uri.getPathSegments().get(1); count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); updateData = true; break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); // 未知URI抛出异常 } - if (count > 0) { + if (count > 0) { // 如果更新了数据 if (updateData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); // 通知便签URI变化 } - getContext().getContentResolver().notifyChange(uri, null); + getContext().getContentResolver().notifyChange(uri, null); // 通知当前URI变化 } return count; } + /** + * 解析选择条件,添加AND连接符 + * @param selection 原始选择条件 + * @return 解析后的选择条件 + */ private String parseSelection(String selection) { return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); } + /** + * 增加便签版本号 + * @param id 便签ID,-1表示不指定 + * @param selection 选择条件 + * @param selectionArgs 选择参数 + */ private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); sql.append(TABLE.NOTE); sql.append(" SET "); sql.append(NoteColumns.VERSION); - sql.append("=" + NoteColumns.VERSION + "+1 "); + sql.append("=" + NoteColumns.VERSION + "+1 "); // 版本号加1 - if (id > 0 || !TextUtils.isEmpty(selection)) { + if (id > 0 || !TextUtils.isEmpty(selection)) { // 如果有ID或选择条件 sql.append(" WHERE "); } - if (id > 0) { + if (id > 0) { // 如果指定了ID sql.append(NoteColumns.ID + "=" + String.valueOf(id)); } - if (!TextUtils.isEmpty(selection)) { + if (!TextUtils.isEmpty(selection)) { // 如果有选择条件 String selectString = id > 0 ? parseSelection(selection) : selection; - for (String args : selectionArgs) { + for (String args : selectionArgs) { // 替换参数 selectString = selectString.replaceFirst("\\?", args); } sql.append(selectString); } - mHelper.getWritableDatabase().execSQL(sql.toString()); + mHelper.getWritableDatabase().execSQL(sql.toString()); // 执行SQL } + /** + * 获取URI对应的MIME类型 + * @param uri 请求的URI + * @return MIME类型字符串 + */ @Override public String getType(Uri uri) { // TODO Auto-generated method stub return null; } - -} +} \ No newline at end of file From 44afe2c8c18b5ec4ce1def0a3bbab082b5c19bf4 Mon Sep 17 00:00:00 2001 From: Wang-YYu-Lu <1756892659@qq.com> Date: Tue, 27 May 2025 09:26:27 +0800 Subject: [PATCH 08/11] =?UTF-8?q?gtask=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/micode/notes/gtask/data/MetaData.java | 55 +++- .../src/net/micode/notes/gtask/data/Node.java | 92 ++++++- .../net/micode/notes/gtask/data/SqlData.java | 129 ++++++--- .../net/micode/notes/gtask/data/SqlNote.java | 257 +++++++++++++----- .../src/net/micode/notes/gtask/data/Task.java | 151 ++++++---- .../net/micode/notes/gtask/data/TaskList.java | 187 ++++++++++--- .../exception/ActionFailureException.java | 31 ++- .../exception/NetworkFailureException.java | 32 ++- .../notes/gtask/remote/GTaskASyncTask.java | 154 +++++++---- .../notes/gtask/remote/GTaskClient.java | 242 ++++++++++++++--- .../notes/gtask/remote/GTaskManager.java | 257 +++++++++++++----- .../notes/gtask/remote/GTaskSyncService.java | 167 ++++++++---- 12 files changed, 1311 insertions(+), 443 deletions(-) diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java b/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java index 3a2050b..f78d05b 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java @@ -14,69 +14,116 @@ * limitations under the License. */ +// 元数据类,用于处理与Google Task相关的元数据信息 package net.micode.notes.gtask.data; +// 导入所需的Android和Java类 import android.database.Cursor; import android.util.Log; +// 导入工具类 import net.micode.notes.tool.GTaskStringUtils; +// 导入JSON处理类 import org.json.JSONException; import org.json.JSONObject; - +// 元数据类,继承自Task基类 public class MetaData extends Task { + // 日志标签,使用类名作为标签 private final static String TAG = MetaData.class.getSimpleName(); + // 关联的Google Task ID private String mRelatedGid = null; + /** + * 设置元数据信息 + * @param gid 关联的Google Task ID + * @param metaInfo 包含元数据的JSON对象 + */ public void setMeta(String gid, JSONObject metaInfo) { try { + // 将Google Task ID添加到元数据中 metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); } catch (JSONException e) { + // 记录添加关联ID失败的错误 Log.e(TAG, "failed to put related gid"); } + // 将JSON对象转换为字符串并设置为备注 setNotes(metaInfo.toString()); + // 设置元数据的名称为固定值 setName(GTaskStringUtils.META_NOTE_NAME); } + /** + * 获取关联的Google Task ID + * @return 关联的Google Task ID + */ public String getRelatedGid() { return mRelatedGid; } + /** + * 检查是否需要保存 + * @return 如果备注不为null则返回true,表示需要保存 + */ @Override public boolean isWorthSaving() { return getNotes() != null; } + /** + * 从远程JSON数据设置内容 + * @param js 包含远程数据的JSON对象 + */ @Override public void setContentByRemoteJSON(JSONObject js) { + // 调用父类方法设置基本内容 super.setContentByRemoteJSON(js); + // 如果备注不为空,尝试解析关联的Google Task ID if (getNotes() != null) { try { + // 从备注字符串创建JSON对象 JSONObject metaInfo = new JSONObject(getNotes().trim()); + // 获取关联的Google Task ID mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); } catch (JSONException e) { + // 记录获取关联ID失败的警告 Log.w(TAG, "failed to get related gid"); + // 将关联ID设为null mRelatedGid = null; } } } + /** + * 从本地JSON数据设置内容(不应被调用) + * @param js 包含本地数据的JSON对象 + */ @Override public void setContentByLocalJSON(JSONObject js) { - // this function should not be called + // 抛出错误,表示该方法不应被调用 throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); } + /** + * 从内容获取本地JSON数据(不应被调用) + * @return 不应被调用,总是抛出异常 + */ @Override public JSONObject getLocalJSONFromContent() { + // 抛出错误,表示该方法不应被调用 throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); } + /** + * 获取同步动作(不应被调用) + * @param c 数据库游标 + * @return 不应被调用,总是抛出异常 + */ @Override public int getSyncAction(Cursor c) { + // 抛出错误,表示该方法不应被调用 throw new IllegalAccessError("MetaData:getSyncAction should not be called"); } - -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/Node.java b/src/Notes-master/src/net/micode/notes/gtask/data/Node.java index 63950e0..b1b27fd 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/Node.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/Node.java @@ -20,82 +20,162 @@ import android.database.Cursor; import org.json.JSONObject; +/** + * 表示Google Tasks同步系统中的一个节点的抽象基类 + * 定义了节点的基本属性和同步操作 + */ public abstract class Node { + // 无同步操作需要执行 public static final int SYNC_ACTION_NONE = 0; + // 将本地节点添加到远程服务器 public static final int SYNC_ACTION_ADD_REMOTE = 1; + // 将远程节点添加到本地数据库 public static final int SYNC_ACTION_ADD_LOCAL = 2; + // 删除远程服务器上的节点 public static final int SYNC_ACTION_DEL_REMOTE = 3; + // 删除本地数据库中的节点 public static final int SYNC_ACTION_DEL_LOCAL = 4; + // 将本地更改更新到远程服务器 public static final int SYNC_ACTION_UPDATE_REMOTE = 5; + // 将远程更改更新到本地数据库 public static final int SYNC_ACTION_UPDATE_LOCAL = 6; + // 本地和远程都有更新,发生冲突 public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; + // 同步过程中发生错误 public static final int SYNC_ACTION_ERROR = 8; + // Google Tasks服务中的唯一标识符 private String mGid; + // 节点名称/标题 private String mName; + // 最后修改时间戳 private long mLastModified; + // 标记节点是否已删除 private boolean mDeleted; + /** + * 默认构造函数,初始化节点属性 + */ public Node() { - mGid = null; - mName = ""; - mLastModified = 0; - mDeleted = false; + mGid = null; // 初始化为空,等待从服务器获取或本地生成 + mName = ""; // 默认空名称 + mLastModified = 0; // 默认时间戳为0 + mDeleted = false; // 默认未删除状态 } + /** + * 创建用于添加节点的JSON同步操作 + * @param actionId 操作ID + * @return 包含创建操作的JSON对象 + */ public abstract JSONObject getCreateAction(int actionId); + /** + * 创建用于更新节点的JSON同步操作 + * @param actionId 操作ID + * @return 包含更新操作的JSON对象 + */ public abstract JSONObject getUpdateAction(int actionId); + /** + * 根据远程JSON数据设置节点内容 + * @param js 包含远程数据的JSON对象 + */ public abstract void setContentByRemoteJSON(JSONObject js); + /** + * 根据本地JSON数据设置节点内容 + * @param js 包含本地数据的JSON对象 + */ public abstract void setContentByLocalJSON(JSONObject js); + /** + * 从节点内容生成用于本地存储的JSON对象 + * @return 包含节点内容的JSON对象 + */ public abstract JSONObject getLocalJSONFromContent(); + /** + * 根据本地数据库光标确定需要执行的同步操作类型 + * @param c 数据库查询返回的光标 + * @return 同步操作类型常量 + */ public abstract int getSyncAction(Cursor c); + // 以下是节点属性的访问器和修改器方法 + + /** + * 设置节点的Google Tasks标识符 + * @param gid Google Tasks服务中的唯一ID + */ public void setGid(String gid) { this.mGid = gid; } + /** + * 设置节点名称 + * @param name 节点名称 + */ public void setName(String name) { this.mName = name; } + /** + * 设置节点最后修改时间 + * @param lastModified 时间戳(毫秒) + */ public void setLastModified(long lastModified) { this.mLastModified = lastModified; } + /** + * 设置节点删除状态 + * @param deleted true表示已删除,false表示未删除 + */ public void setDeleted(boolean deleted) { this.mDeleted = deleted; } + /** + * 获取节点的Google Tasks标识符 + * @return Google Tasks ID + */ public String getGid() { return this.mGid; } + /** + * 获取节点名称 + * @return 节点名称 + */ public String getName() { return this.mName; } + /** + * 获取节点最后修改时间 + * @return 时间戳(毫秒) + */ public long getLastModified() { return this.mLastModified; } + /** + * 获取节点删除状态 + * @return true表示已删除,false表示未删除 + */ public boolean getDeleted() { return this.mDeleted; } - -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/SqlData.java b/src/Notes-master/src/net/micode/notes/gtask/data/SqlData.java index d3ec3be..8e3c7c6 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/SqlData.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/SqlData.java @@ -34,61 +34,72 @@ import net.micode.notes.gtask.exception.ActionFailureException; import org.json.JSONException; import org.json.JSONObject; - +/** + * 处理与本地SQLite数据库中笔记数据的交互 + * 提供从数据库加载数据、更新数据和提交更改的功能 + */ public class SqlData { private static final String TAG = SqlData.class.getSimpleName(); + // 无效ID值,用于标识尚未从数据库获取ID的新数据 private static final int INVALID_ID = -99999; + // 查询数据时使用的投影列 public static final String[] PROJECTION_DATA = new String[] { - DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, - DataColumns.DATA3 + DataColumns.ID, // 数据ID + DataColumns.MIME_TYPE, // 数据MIME类型 + DataColumns.CONTENT, // 数据内容 + DataColumns.DATA1, // 额外数据字段1 + DataColumns.DATA3 // 额外数据字段3 }; + // 投影列的索引位置 public static final int DATA_ID_COLUMN = 0; - public static final int DATA_MIME_TYPE_COLUMN = 1; - public static final int DATA_CONTENT_COLUMN = 2; - public static final int DATA_CONTENT_DATA_1_COLUMN = 3; - public static final int DATA_CONTENT_DATA_3_COLUMN = 4; - private ContentResolver mContentResolver; - - private boolean mIsCreate; - - private long mDataId; - - private String mDataMimeType; - - private String mDataContent; - - private long mDataContentData1; - - private String mDataContentData3; - - private ContentValues mDiffDataValues; - + private ContentResolver mContentResolver; // 内容解析器,用于与内容提供者交互 + private boolean mIsCreate; // 标记数据是否为新创建 + private long mDataId; // 数据ID + private String mDataMimeType; // 数据MIME类型 + private String mDataContent; // 数据内容 + private long mDataContentData1; // 额外数据字段1 + private String mDataContentData3; // 额外数据字段3 + private ContentValues mDiffDataValues; // 存储与原始数据不同的值,用于更新 + + /** + * 构造函数,用于创建新的SQL数据对象 + * @param context 应用上下文 + */ public SqlData(Context context) { mContentResolver = context.getContentResolver(); - mIsCreate = true; - mDataId = INVALID_ID; - mDataMimeType = DataConstants.NOTE; - mDataContent = ""; - mDataContentData1 = 0; - mDataContentData3 = ""; - mDiffDataValues = new ContentValues(); + mIsCreate = true; // 标记为新创建的数据 + mDataId = INVALID_ID; // 初始化为无效ID + mDataMimeType = DataConstants.NOTE; // 默认MIME类型为笔记 + mDataContent = ""; // 空内容 + mDataContentData1 = 0; // 初始化数据字段1 + mDataContentData3 = ""; // 初始化数据字段3 + mDiffDataValues = new ContentValues(); // 初始化差异值容器 } + /** + * 构造函数,用于从数据库游标加载现有数据 + * @param context 应用上下文 + * @param c 包含数据的数据库游标 + */ public SqlData(Context context, Cursor c) { mContentResolver = context.getContentResolver(); - mIsCreate = false; - loadFromCursor(c); - mDiffDataValues = new ContentValues(); + mIsCreate = false; // 标记为现有数据 + loadFromCursor(c); // 从游标加载数据 + mDiffDataValues = new ContentValues(); // 初始化差异值容器 } + /** + * 从数据库游标加载数据 + * @param c 包含数据的游标 + */ private void loadFromCursor(Cursor c) { mDataId = c.getLong(DATA_ID_COLUMN); mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); @@ -97,13 +108,20 @@ public class SqlData { mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } + /** + * 根据JSON对象设置数据内容 + * @param js 包含数据的JSON对象 + * @throws JSONException 如果JSON解析失败 + */ public void setContent(JSONObject js) throws JSONException { + // 从JSON中获取ID并设置 long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; if (mIsCreate || mDataId != dataId) { mDiffDataValues.put(DataColumns.ID, dataId); } mDataId = dataId; + // 从JSON中获取MIME类型并设置 String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE) : DataConstants.NOTE; if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { @@ -111,18 +129,21 @@ public class SqlData { } mDataMimeType = dataMimeType; + // 从JSON中获取内容并设置 String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; if (mIsCreate || !mDataContent.equals(dataContent)) { mDiffDataValues.put(DataColumns.CONTENT, dataContent); } mDataContent = dataContent; + // 从JSON中获取数据字段1并设置 long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; if (mIsCreate || mDataContentData1 != dataContentData1) { mDiffDataValues.put(DataColumns.DATA1, dataContentData1); } mDataContentData1 = dataContentData1; + // 从JSON中获取数据字段3并设置 String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { mDiffDataValues.put(DataColumns.DATA3, dataContentData3); @@ -130,9 +151,14 @@ public class SqlData { mDataContentData3 = dataContentData3; } + /** + * 将数据内容转换为JSON对象 + * @return 包含数据的JSON对象 + * @throws JSONException 如果JSON构建失败 + */ public JSONObject getContent() throws JSONException { if (mIsCreate) { - Log.e(TAG, "it seems that we haven't created this in database yet"); + Log.e(TAG, "数据尚未提交到数据库,无法获取内容"); return null; } JSONObject js = new JSONObject(); @@ -144,46 +170,59 @@ public class SqlData { return js; } + /** + * 将数据更改提交到数据库 + * @param noteId 关联的笔记ID + * @param validateVersion 是否验证版本 + * @param version 版本号 + */ public void commit(long noteId, boolean validateVersion, long version) { - if (mIsCreate) { + // 创建新数据 if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { - mDiffDataValues.remove(DataColumns.ID); + mDiffDataValues.remove(DataColumns.ID); // 移除无效ID } - mDiffDataValues.put(DataColumns.NOTE_ID, noteId); + mDiffDataValues.put(DataColumns.NOTE_ID, noteId); // 设置关联笔记ID Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); try { - mDataId = Long.valueOf(uri.getPathSegments().get(1)); + mDataId = Long.valueOf(uri.getPathSegments().get(1)); // 获取新生成的ID } catch (NumberFormatException e) { - Log.e(TAG, "Get note id error :" + e.toString()); - throw new ActionFailureException("create note failed"); + Log.e(TAG, "获取笔记ID错误: " + e.toString()); + throw new ActionFailureException("创建笔记失败"); } } else { + // 更新现有数据 if (mDiffDataValues.size() > 0) { int result = 0; if (!validateVersion) { + // 不验证版本直接更新 result = mContentResolver.update(ContentUris.withAppendedId( Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); } else { + // 验证版本后更新,确保版本一致 result = mContentResolver.update(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, + Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE + " WHERE " + NoteColumns.VERSION + "=?)", new String[] { String.valueOf(noteId), String.valueOf(version) }); } if (result == 0) { - Log.w(TAG, "there is no update. maybe user updates note when syncing"); + Log.w(TAG, "没有数据更新,可能用户在同步时修改了笔记"); } } } - mDiffDataValues.clear(); - mIsCreate = false; + mDiffDataValues.clear(); // 清空差异值 + mIsCreate = false; // 标记为已创建 } + /** + * 获取数据ID + * @return 数据ID + */ public long getId() { return mDataId; } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java b/src/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java index 79a4095..ffc529b 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java @@ -14,8 +14,10 @@ * limitations under the License. */ +// 数据库笔记实体类,负责处理便签数据的本地存储和同步操作 package net.micode.notes.gtask.data; +// Android基础组件导入 import android.appwidget.AppWidgetManager; import android.content.ContentResolver; import android.content.ContentValues; @@ -24,6 +26,7 @@ import android.database.Cursor; import android.net.Uri; import android.util.Log; +// 项目内部类导入 import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.NoteColumns; @@ -31,18 +34,25 @@ import net.micode.notes.gtask.exception.ActionFailureException; import net.micode.notes.tool.GTaskStringUtils; import net.micode.notes.tool.ResourceParser; +// JSON处理类导入 import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +// Java工具类导入 import java.util.ArrayList; - +/** + * SQLite数据库笔记操作类,封装便签的CRUD操作和Google Task同步功能 + */ public class SqlNote { + // 日志标签 private static final String TAG = SqlNote.class.getSimpleName(); + // 无效ID常量 private static final int INVALID_ID = -99999; + // 笔记表查询字段投影 public static final String[] PROJECTION_NOTE = new String[] { NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID, NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE, @@ -52,80 +62,92 @@ public class SqlNote { NoteColumns.VERSION }; + // 字段列索引常量定义 public static final int ID_COLUMN = 0; - public static final int ALERTED_DATE_COLUMN = 1; - public static final int BG_COLOR_ID_COLUMN = 2; - public static final int CREATED_DATE_COLUMN = 3; - public static final int HAS_ATTACHMENT_COLUMN = 4; - public static final int MODIFIED_DATE_COLUMN = 5; - public static final int NOTES_COUNT_COLUMN = 6; - public static final int PARENT_ID_COLUMN = 7; - public static final int SNIPPET_COLUMN = 8; - public static final int TYPE_COLUMN = 9; - public static final int WIDGET_ID_COLUMN = 10; - public static final int WIDGET_TYPE_COLUMN = 11; - public static final int SYNC_ID_COLUMN = 12; - public static final int LOCAL_MODIFIED_COLUMN = 13; - public static final int ORIGIN_PARENT_ID_COLUMN = 14; - public static final int GTASK_ID_COLUMN = 15; - public static final int VERSION_COLUMN = 16; + // 上下文对象 private Context mContext; + // 内容解析器 private ContentResolver mContentResolver; + // 是否为新创建标志 private boolean mIsCreate; + // 笔记ID private long mId; + // 提醒日期 private long mAlertDate; + // 背景颜色ID private int mBgColorId; + // 创建日期 private long mCreatedDate; + // 是否有附件标志 private int mHasAttachment; + // 修改日期 private long mModifiedDate; + // 父节点ID private long mParentId; + // 内容摘要 private String mSnippet; + // 笔记类型 private int mType; + // 小部件ID private int mWidgetId; + // 小部件类型 private int mWidgetType; + // 原始父节点ID private long mOriginParent; + // 数据版本号 private long mVersion; + // 差异内容值对象 private ContentValues mDiffNoteValues; + // 关联数据列表 private ArrayList mDataList; + /** + * 构造函数(新建笔记) + * @param context 上下文对象 + */ public SqlNote(Context context) { + // 初始化上下文和内容解析器 mContext = context; mContentResolver = context.getContentResolver(); + + // 设置新建标志 mIsCreate = true; + + // 初始化默认值 mId = INVALID_ID; mAlertDate = 0; mBgColorId = ResourceParser.getDefaultBgId(context); @@ -139,40 +161,65 @@ public class SqlNote { mWidgetType = Notes.TYPE_WIDGET_INVALIDE; mOriginParent = 0; mVersion = 0; + + // 初始化差异值和数据列表 mDiffNoteValues = new ContentValues(); mDataList = new ArrayList(); } + /** + * 构造函数(从游标加载) + * @param context 上下文对象 + * @param c 数据库游标 + */ public SqlNote(Context context, Cursor c) { mContext = context; mContentResolver = context.getContentResolver(); mIsCreate = false; + + // 从游标加载数据 loadFromCursor(c); mDataList = new ArrayList(); + + // 如果是笔记类型,加载关联数据 if (mType == Notes.TYPE_NOTE) loadDataContent(); + mDiffNoteValues = new ContentValues(); } + /** + * 构造函数(从ID加载) + * @param context 上下文对象 + * @param id 笔记ID + */ public SqlNote(Context context, long id) { mContext = context; mContentResolver = context.getContentResolver(); mIsCreate = false; + + // 从ID加载数据 loadFromCursor(id); mDataList = new ArrayList(); + + // 如果是笔记类型,加载关联数据 if (mType == Notes.TYPE_NOTE) loadDataContent(); - mDiffNoteValues = new ContentValues(); + mDiffNoteValues = new ContentValues(); } + /** + * 从ID加载笔记数据 + * @param id 笔记ID + */ private void loadFromCursor(long id) { Cursor c = null; try { + // 查询指定ID的笔记 c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", - new String[] { - String.valueOf(id) - }, null); + new String[] { String.valueOf(id) }, null); + if (c != null) { c.moveToNext(); loadFromCursor(c); @@ -185,7 +232,12 @@ public class SqlNote { } } + /** + * 从游标加载笔记数据 + * @param c 数据库游标 + */ private void loadFromCursor(Cursor c) { + // 从游标读取各字段值 mId = c.getLong(ID_COLUMN); mAlertDate = c.getLong(ALERTED_DATE_COLUMN); mBgColorId = c.getInt(BG_COLOR_ID_COLUMN); @@ -200,19 +252,24 @@ public class SqlNote { mVersion = c.getLong(VERSION_COLUMN); } + /** + * 加载笔记关联数据内容 + */ private void loadDataContent() { Cursor c = null; mDataList.clear(); try { + // 查询关联数据 c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, - "(note_id=?)", new String[] { - String.valueOf(mId) - }, null); + "(note_id=?)", new String[] { String.valueOf(mId) }, null); + if (c != null) { if (c.getCount() == 0) { Log.w(TAG, "it seems that the note has not data"); return; } + + // 遍历游标创建数据对象 while (c.moveToNext()) { SqlData data = new SqlData(mContext, c); mDataList.add(data); @@ -226,85 +283,93 @@ public class SqlNote { } } + /** + * 从JSON对象设置笔记内容 + * @param js JSON对象 + * @return 是否设置成功 + */ public boolean setContent(JSONObject js) { try { + // 获取笔记节点 JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + + // 处理系统文件夹 if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { Log.w(TAG, "cannot set system folder"); - } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { - // for folder we can only update the snnipet and type - String snippet = note.has(NoteColumns.SNIPPET) ? note - .getString(NoteColumns.SNIPPET) : ""; + } + // 处理普通文件夹 + else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { + // 更新摘要和类型 + String snippet = note.has(NoteColumns.SNIPPET) ? note.getString(NoteColumns.SNIPPET) : ""; if (mIsCreate || !mSnippet.equals(snippet)) { mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); } mSnippet = snippet; - int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) - : Notes.TYPE_NOTE; + int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) : Notes.TYPE_NOTE; if (mIsCreate || mType != type) { mDiffNoteValues.put(NoteColumns.TYPE, type); } mType = type; - } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { + } + // 处理普通笔记 + else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { + // 获取数据数组 JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + + // 更新各字段值 long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID; if (mIsCreate || mId != id) { mDiffNoteValues.put(NoteColumns.ID, id); } mId = id; - long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note - .getLong(NoteColumns.ALERTED_DATE) : 0; + long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note.getLong(NoteColumns.ALERTED_DATE) : 0; if (mIsCreate || mAlertDate != alertDate) { mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate); } mAlertDate = alertDate; - int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note - .getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext); + int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note.getInt(NoteColumns.BG_COLOR_ID) + : ResourceParser.getDefaultBgId(mContext); if (mIsCreate || mBgColorId != bgColorId) { mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId); } mBgColorId = bgColorId; - long createDate = note.has(NoteColumns.CREATED_DATE) ? note - .getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis(); + long createDate = note.has(NoteColumns.CREATED_DATE) ? note.getLong(NoteColumns.CREATED_DATE) + : System.currentTimeMillis(); if (mIsCreate || mCreatedDate != createDate) { mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate); } mCreatedDate = createDate; - int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note - .getInt(NoteColumns.HAS_ATTACHMENT) : 0; + int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note.getInt(NoteColumns.HAS_ATTACHMENT) : 0; if (mIsCreate || mHasAttachment != hasAttachment) { mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment); } mHasAttachment = hasAttachment; - long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note - .getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis(); + long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note.getLong(NoteColumns.MODIFIED_DATE) + : System.currentTimeMillis(); if (mIsCreate || mModifiedDate != modifiedDate) { mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate); } mModifiedDate = modifiedDate; - long parentId = note.has(NoteColumns.PARENT_ID) ? note - .getLong(NoteColumns.PARENT_ID) : 0; + long parentId = note.has(NoteColumns.PARENT_ID) ? note.getLong(NoteColumns.PARENT_ID) : 0; if (mIsCreate || mParentId != parentId) { mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId); } mParentId = parentId; - String snippet = note.has(NoteColumns.SNIPPET) ? note - .getString(NoteColumns.SNIPPET) : ""; + String snippet = note.has(NoteColumns.SNIPPET) ? note.getString(NoteColumns.SNIPPET) : ""; if (mIsCreate || !mSnippet.equals(snippet)) { mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); } mSnippet = snippet; - int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) - : Notes.TYPE_NOTE; + int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) : Notes.TYPE_NOTE; if (mIsCreate || mType != type) { mDiffNoteValues.put(NoteColumns.TYPE, type); } @@ -317,23 +382,25 @@ public class SqlNote { } mWidgetId = widgetId; - int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note - .getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE; + int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note.getInt(NoteColumns.WIDGET_TYPE) + : Notes.TYPE_WIDGET_INVALIDE; if (mIsCreate || mWidgetType != widgetType) { mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType); } mWidgetType = widgetType; - long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note - .getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; + long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; if (mIsCreate || mOriginParent != originParent) { mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent); } mOriginParent = originParent; + // 处理关联数据 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); SqlData sqlData = null; + + // 查找已有数据 if (data.has(DataColumns.ID)) { long dataId = data.getLong(DataColumns.ID); for (SqlData temp : mDataList) { @@ -343,11 +410,13 @@ public class SqlNote { } } + // 创建新数据对象 if (sqlData == null) { sqlData = new SqlData(mContext); mDataList.add(sqlData); } + // 设置数据内容 sqlData.setContent(data); } } @@ -359,17 +428,25 @@ public class SqlNote { return true; } + /** + * 获取笔记内容的JSON表示 + * @return JSON对象 + */ public JSONObject getContent() { try { JSONObject js = new JSONObject(); + // 检查是否已创建 if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); return null; } JSONObject note = new JSONObject(); + + // 处理普通笔记 if (mType == Notes.TYPE_NOTE) { + // 添加笔记字段 note.put(NoteColumns.ID, mId); note.put(NoteColumns.ALERTED_DATE, mAlertDate); note.put(NoteColumns.BG_COLOR_ID, mBgColorId); @@ -384,6 +461,7 @@ public class SqlNote { note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent); js.put(GTaskStringUtils.META_HEAD_NOTE, note); + // 添加关联数据 JSONArray dataArray = new JSONArray(); for (SqlData sqlData : mDataList) { JSONObject data = sqlData.getContent(); @@ -392,7 +470,9 @@ public class SqlNote { } } js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); - } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { + } + // 处理文件夹和系统文件夹 + else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { note.put(NoteColumns.ID, mId); note.put(NoteColumns.TYPE, mType); note.put(NoteColumns.SNIPPET, mSnippet); @@ -407,45 +487,83 @@ public class SqlNote { return null; } + /** + * 设置父节点ID + * @param id 父节点ID + */ public void setParentId(long id) { mParentId = id; mDiffNoteValues.put(NoteColumns.PARENT_ID, id); } + /** + * 设置Google Task ID + * @param gid Google Task ID + */ public void setGtaskId(String gid) { mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); } + /** + * 设置同步ID + * @param syncId 同步ID + */ public void setSyncId(long syncId) { mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); } + /** + * 重置本地修改标志 + */ public void resetLocalModified() { mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); } + /** + * 获取笔记ID + * @return 笔记ID + */ public long getId() { return mId; } + /** + * 获取父节点ID + * @return 父节点ID + */ public long getParentId() { return mParentId; } + /** + * 获取内容摘要 + * @return 内容摘要 + */ public String getSnippet() { return mSnippet; } + /** + * 检查是否为笔记类型 + * @return 是否为笔记类型 + */ public boolean isNoteType() { return mType == Notes.TYPE_NOTE; } + /** + * 提交更改到数据库 + * @param validateVersion 是否验证版本号 + */ public void commit(boolean validateVersion) { + // 处理新建笔记 if (mIsCreate) { + // 处理无效ID if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { mDiffNoteValues.remove(NoteColumns.ID); } + // 插入新笔记 Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues); try { mId = Long.valueOf(uri.getPathSegments().get(1)); @@ -453,40 +571,50 @@ public class SqlNote { Log.e(TAG, "Get note id error :" + e.toString()); throw new ActionFailureException("create note failed"); } + + // 检查ID是否有效 if (mId == 0) { throw new IllegalStateException("Create thread id failed"); } + // 提交关联数据 if (mType == Notes.TYPE_NOTE) { for (SqlData sqlData : mDataList) { sqlData.commit(mId, false, -1); } } - } else { + } + // 处理已有笔记更新 + else { + // 检查ID有效性 if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) { Log.e(TAG, "No such note"); throw new IllegalStateException("Try to update note with invalid id"); } + + // 如果有差异值需要更新 if (mDiffNoteValues.size() > 0) { mVersion ++; int result = 0; + + // 根据是否验证版本选择更新方式 if (!validateVersion) { - result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" - + NoteColumns.ID + "=?)", new String[] { - String.valueOf(mId) - }); + result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, + "(" + NoteColumns.ID + "=?)", + new String[] { String.valueOf(mId) }); } else { - result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" - + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", - new String[] { - String.valueOf(mId), String.valueOf(mVersion) - }); + result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, + "(" + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", + new String[] { String.valueOf(mId), String.valueOf(mVersion) }); } + + // 检查更新结果 if (result == 0) { Log.w(TAG, "there is no update. maybe user updates note when syncing"); } } + // 提交关联数据 if (mType == Notes.TYPE_NOTE) { for (SqlData sqlData : mDataList) { sqlData.commit(mId, validateVersion, mVersion); @@ -494,12 +622,13 @@ public class SqlNote { } } - // refresh local info + // 刷新本地数据 loadFromCursor(mId); if (mType == Notes.TYPE_NOTE) loadDataContent(); + // 重置差异值和创建标志 mDiffNoteValues.clear(); mIsCreate = false; } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/Task.java b/src/Notes-master/src/net/micode/notes/gtask/data/Task.java index 6a19454..cb35d4d 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/Task.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/Task.java @@ -2,16 +2,13 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ package net.micode.notes.gtask.data; @@ -31,44 +28,48 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; - +/** + * 表示Google Tasks中的任务实体 + * 负责与远程任务数据和本地笔记数据的转换和同步 + */ public class Task extends Node { private static final String TAG = Task.class.getSimpleName(); - private boolean mCompleted; - - private String mNotes; - - private JSONObject mMetaInfo; - - private Task mPriorSibling; - - private TaskList mParent; + private boolean mCompleted; // 任务完成状态 + private String mNotes; // 任务备注内容 + private JSONObject mMetaInfo; // 任务元信息(本地存储格式) + private Task mPriorSibling; // 前一个兄弟任务(用于排序) + private TaskList mParent; // 所属任务列表 public Task() { super(); - mCompleted = false; - mNotes = null; - mPriorSibling = null; - mParent = null; - mMetaInfo = null; + mCompleted = false; // 默认未完成 + mNotes = null; // 默认无备注 + mPriorSibling = null; // 默认无前兄弟任务 + mParent = null; // 默认无父任务列表 + mMetaInfo = null; // 默认无元信息 } + /** + * 生成创建任务的JSON请求 + * @param actionId 操作ID(用于标识同步操作) + * @return 创建任务的JSON对象 + */ public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); try { - // action_type + // 设置操作类型为创建任务 js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); - // action_id + // 设置操作ID js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // index + // 设置任务在父列表中的索引位置 js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this)); - // entity_delta + // 设置任务实体信息 JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); @@ -79,17 +80,15 @@ public class Task extends Node { } js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - // parent_id + // 设置父任务列表ID和类型 js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid()); - - // dest_parent_type js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE, GTaskStringUtils.GTASK_JSON_TYPE_GROUP); - // list_id + // 设置所属列表ID(与父ID相同) js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid()); - // prior_sibling_id + // 设置前一个兄弟任务ID(用于排序) if (mPriorSibling != null) { js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid()); } @@ -103,21 +102,26 @@ public class Task extends Node { return js; } + /** + * 生成更新任务的JSON请求 + * @param actionId 操作ID + * @return 更新任务的JSON对象 + */ public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); try { - // action_type + // 设置操作类型为更新任务 js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - // action_id + // 设置操作ID js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // id + // 设置要更新的任务ID js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - // entity_delta + // 设置要更新的任务实体信息 JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); if (getNotes() != null) { @@ -135,35 +139,39 @@ public class Task extends Node { return js; } + /** + * 从远程JSON数据设置任务内容 + * @param js 包含远程任务数据的JSON对象 + */ public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { - // id + // 从JSON中提取任务ID并设置 if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); } - // last_modified + // 提取最后修改时间戳 if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); } - // name + // 提取任务名称 if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); } - // notes + // 提取任务备注 if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) { setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); } - // deleted + // 提取任务删除状态 if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) { setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); } - // completed + // 提取任务完成状态 if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) { setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED)); } @@ -175,6 +183,10 @@ public class Task extends Node { } } + /** + * 从本地JSON数据设置任务内容 + * @param js 包含本地笔记数据的JSON对象 + */ public void setContentByLocalJSON(JSONObject js) { if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) || !js.has(GTaskStringUtils.META_HEAD_DATA)) { @@ -182,14 +194,17 @@ public class Task extends Node { } try { + // 提取笔记头部信息和数据数组 JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + // 验证笔记类型是否为普通笔记 if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) { Log.e(TAG, "invalid type"); return; } + // 从数据数组中提取任务名称 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { @@ -204,16 +219,21 @@ public class Task extends Node { } } + /** + * 根据任务内容生成本地JSON格式数据 + * @return 表示本地笔记的JSON对象 + */ public JSONObject getLocalJSONFromContent() { String name = getName(); try { if (mMetaInfo == null) { - // new task created from web + // 处理从网页创建的新任务(无元信息) if (name == null) { Log.w(TAG, "the note seems to be an empty one"); return null; } + // 构建基本的本地笔记JSON结构 JSONObject js = new JSONObject(); JSONObject note = new JSONObject(); JSONArray dataArray = new JSONArray(); @@ -225,10 +245,11 @@ public class Task extends Node { js.put(GTaskStringUtils.META_HEAD_NOTE, note); return js; } else { - // synced task + // 处理已同步过的任务(有元信息) JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + // 更新任务名称 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { @@ -247,6 +268,10 @@ public class Task extends Node { } } + /** + * 设置任务的元信息(从本地存储的元数据中解析) + * @param metaData 包含元信息的对象 + */ public void setMetaInfo(MetaData metaData) { if (metaData != null && metaData.getNotes() != null) { try { @@ -258,48 +283,57 @@ public class Task extends Node { } } + /** + * 根据本地数据库记录和任务状态确定同步动作类型 + * @param c 包含本地笔记数据的游标 + * @return 同步动作类型(见常量定义) + */ public int getSyncAction(Cursor c) { try { JSONObject noteInfo = null; + // 从元信息中获取笔记头部信息 if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) { noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); } if (noteInfo == null) { Log.w(TAG, "it seems that note meta has been deleted"); - return SYNC_ACTION_UPDATE_REMOTE; + return SYNC_ACTION_UPDATE_REMOTE; // 元信息丢失,需要更新远程 } if (!noteInfo.has(NoteColumns.ID)) { Log.w(TAG, "remote note id seems to be deleted"); - return SYNC_ACTION_UPDATE_LOCAL; + return SYNC_ACTION_UPDATE_LOCAL; // 缺少笔记ID,需要更新本地 } - // validate the note id now + // 验证笔记ID是否匹配 if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) { Log.w(TAG, "note id doesn't match"); - return SYNC_ACTION_UPDATE_LOCAL; + return SYNC_ACTION_UPDATE_LOCAL; // ID不匹配,需要更新本地 } + // 判断本地是否有修改 if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // there is no local update + // 本地没有修改 if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // no update both side + // 两边都没有更新 return SYNC_ACTION_NONE; } else { - // apply remote to local + // 远程有更新,应用到本地 return SYNC_ACTION_UPDATE_LOCAL; } } else { - // validate gtask id + // 本地有修改 + // 验证GTask ID是否匹配 if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { Log.e(TAG, "gtask id doesn't match"); - return SYNC_ACTION_ERROR; + return SYNC_ACTION_ERROR; // GTask ID不匹配,同步错误 } if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // local modification only + // 只有本地修改,更新远程 return SYNC_ACTION_UPDATE_REMOTE; } else { + // 本地和远程都有修改,发生冲突 return SYNC_ACTION_UPDATE_CONFLICT; } } @@ -308,14 +342,21 @@ public class Task extends Node { e.printStackTrace(); } - return SYNC_ACTION_ERROR; + return SYNC_ACTION_ERROR; // 发生异常,返回错误 } + /** + * 判断任务是否值得保存(有有效内容) + * @return 如果任务有有效内容返回true,否则返回false + */ public boolean isWorthSaving() { + // 任务有元信息,或有非空名称,或有非空备注时值得保存 return mMetaInfo != null || (getName() != null && getName().trim().length() > 0) || (getNotes() != null && getNotes().trim().length() > 0); } + // 以下为属性的setter和getter方法 + public void setCompleted(boolean completed) { this.mCompleted = completed; } @@ -348,4 +389,4 @@ public class Task extends Node { return this.mParent; } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/TaskList.java b/src/Notes-master/src/net/micode/notes/gtask/data/TaskList.java index 4ea21c5..d204618 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/TaskList.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/TaskList.java @@ -2,16 +2,13 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ package net.micode.notes.gtask.data; @@ -29,35 +26,42 @@ import org.json.JSONObject; import java.util.ArrayList; - +/** + * 表示Google Tasks中的任务列表(相当于文件夹) + * 负责与远程任务列表数据和本地笔记数据的转换和同步 + */ public class TaskList extends Node { private static final String TAG = TaskList.class.getSimpleName(); - private int mIndex; - - private ArrayList mChildren; + private int mIndex; // 任务列表在父级中的排序索引 + private ArrayList mChildren; // 包含的子任务列表 public TaskList() { super(); - mChildren = new ArrayList(); - mIndex = 1; + mChildren = new ArrayList(); // 初始化子任务列表 + mIndex = 1; // 默认索引为1 } + /** + * 生成创建任务列表的JSON请求 + * @param actionId 操作ID(用于标识同步操作) + * @return 创建任务列表的JSON对象 + */ public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); try { - // action_type + // 设置操作类型为创建任务列表 js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); - // action_id + // 设置操作ID js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // index + // 设置任务列表的排序索引 js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); - // entity_delta + // 设置任务列表实体信息 JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); @@ -74,21 +78,26 @@ public class TaskList extends Node { return js; } + /** + * 生成更新任务列表的JSON请求 + * @param actionId 操作ID + * @return 更新任务列表的JSON对象 + */ public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); try { - // action_type + // 设置操作类型为更新任务列表 js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - // action_id + // 设置操作ID js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // id + // 设置要更新的任务列表ID js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - // entity_delta + // 设置要更新的任务列表实体信息 JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); @@ -103,20 +112,24 @@ public class TaskList extends Node { return js; } + /** + * 从远程JSON数据设置任务列表内容 + * @param js 包含远程任务列表数据的JSON对象 + */ public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { - // id + // 从JSON中提取任务列表ID并设置 if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); } - // last_modified + // 提取最后修改时间戳 if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); } - // name + // 提取任务列表名称 if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); } @@ -129,23 +142,30 @@ public class TaskList extends Node { } } + /** + * 从本地JSON数据设置任务列表内容 + * @param js 包含本地笔记数据的JSON对象 + */ public void setContentByLocalJSON(JSONObject js) { if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); } try { + // 提取笔记头部信息 JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + // 根据笔记类型设置任务列表名称 if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { + // 普通文件夹 String name = folder.getString(NoteColumns.SNIPPET); - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name); + setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name); // 添加前缀标识为MIUI文件夹 } else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { + // 系统文件夹 if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT); else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_CALL_NOTE); + setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE); else Log.e(TAG, "invalid system folder"); } else { @@ -157,16 +177,24 @@ public class TaskList extends Node { } } + /** + * 根据任务列表内容生成本地JSON格式数据 + * @return 表示本地笔记的JSON对象 + */ public JSONObject getLocalJSONFromContent() { try { JSONObject js = new JSONObject(); JSONObject folder = new JSONObject(); + // 处理任务列表名称,移除可能的前缀 String folderName = getName(); if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)) - folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(), - folderName.length()); + folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length()); + + // 设置文件夹摘要(名称) folder.put(NoteColumns.SNIPPET, folderName); + + // 根据名称判断文件夹类型(系统文件夹或普通文件夹) if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT) || folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE)) folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); @@ -183,28 +211,35 @@ public class TaskList extends Node { } } + /** + * 根据本地数据库记录和任务列表状态确定同步动作类型 + * @param c 包含本地笔记数据的游标 + * @return 同步动作类型(见常量定义) + */ public int getSyncAction(Cursor c) { try { + // 判断本地是否有修改 if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // there is no local update + // 本地没有修改 if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // no update both side + // 两边都没有更新 return SYNC_ACTION_NONE; } else { - // apply remote to local + // 远程有更新,应用到本地 return SYNC_ACTION_UPDATE_LOCAL; } } else { - // validate gtask id + // 本地有修改 + // 验证GTask ID是否匹配 if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { Log.e(TAG, "gtask id doesn't match"); - return SYNC_ACTION_ERROR; + return SYNC_ACTION_ERROR; // GTask ID不匹配,同步错误 } if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // local modification only + // 只有本地修改,更新远程 return SYNC_ACTION_UPDATE_REMOTE; } else { - // for folder conflicts, just apply local modification + // 本地和远程都有修改,对于文件夹冲突,直接应用本地修改 return SYNC_ACTION_UPDATE_REMOTE; } } @@ -213,27 +248,43 @@ public class TaskList extends Node { e.printStackTrace(); } - return SYNC_ACTION_ERROR; + return SYNC_ACTION_ERROR; // 发生异常,返回错误 } + // 以下为任务列表管理方法 + + /** + * 获取子任务数量 + * @return 子任务数量 + */ public int getChildTaskCount() { return mChildren.size(); } + /** + * 添加子任务到任务列表末尾 + * @param task 要添加的任务 + * @return 添加成功返回true,否则返回false + */ public boolean addChildTask(Task task) { boolean ret = false; if (task != null && !mChildren.contains(task)) { ret = mChildren.add(task); if (ret) { - // need to set prior sibling and parent - task.setPriorSibling(mChildren.isEmpty() ? null : mChildren - .get(mChildren.size() - 1)); + // 设置任务的前一个兄弟任务和父任务列表 + task.setPriorSibling(mChildren.isEmpty() ? null : mChildren.get(mChildren.size() - 1)); task.setParent(this); } } return ret; } + /** + * 在指定位置添加子任务 + * @param task 要添加的任务 + * @param index 指定位置索引 + * @return 添加成功返回true,否则返回false + */ public boolean addChildTask(Task task, int index) { if (index < 0 || index > mChildren.size()) { Log.e(TAG, "add child task: invalid index"); @@ -244,7 +295,7 @@ public class TaskList extends Node { if (task != null && pos == -1) { mChildren.add(index, task); - // update the task list + // 更新任务列表中的前后关系 Task preTask = null; Task afterTask = null; if (index != 0) @@ -260,6 +311,11 @@ public class TaskList extends Node { return true; } + /** + * 从任务列表中移除子任务 + * @param task 要移除的任务 + * @return 移除成功返回true,否则返回false + */ public boolean removeChildTask(Task task) { boolean ret = false; int index = mChildren.indexOf(task); @@ -267,11 +323,11 @@ public class TaskList extends Node { ret = mChildren.remove(task); if (ret) { - // reset prior sibling and parent + // 重置任务的前一个兄弟任务和父任务列表 task.setPriorSibling(null); task.setParent(null); - // update the task list + // 更新任务列表中的前后关系 if (index != mChildren.size()) { mChildren.get(index).setPriorSibling( index == 0 ? null : mChildren.get(index - 1)); @@ -281,8 +337,13 @@ public class TaskList extends Node { return ret; } + /** + * 移动子任务到指定位置 + * @param task 要移动的任务 + * @param index 目标位置索引 + * @return 移动成功返回true,否则返回false + */ public boolean moveChildTask(Task task, int index) { - if (index < 0 || index >= mChildren.size()) { Log.e(TAG, "move child task: invalid index"); return false; @@ -296,9 +357,16 @@ public class TaskList extends Node { if (pos == index) return true; + + // 通过先移除再添加的方式实现移动 return (removeChildTask(task) && addChildTask(task, index)); } + /** + * 根据GTask ID查找子任务 + * @param gid GTask ID + * @return 找到的任务,未找到返回null + */ public Task findChildTaskByGid(String gid) { for (int i = 0; i < mChildren.size(); i++) { Task t = mChildren.get(i); @@ -309,10 +377,20 @@ public class TaskList extends Node { return null; } + /** + * 获取子任务在列表中的索引位置 + * @param task 任务对象 + * @return 索引位置,未找到返回-1 + */ public int getChildTaskIndex(Task task) { return mChildren.indexOf(task); } + /** + * 根据索引位置获取子任务 + * @param index 索引位置 + * @return 任务对象,索引无效返回null + */ public Task getChildTaskByIndex(int index) { if (index < 0 || index >= mChildren.size()) { Log.e(TAG, "getTaskByIndex: invalid index"); @@ -321,6 +399,11 @@ public class TaskList extends Node { return mChildren.get(index); } + /** + * 根据GTask ID获取子任务(与findChildTaskByGid功能相同) + * @param gid GTask ID + * @return 任务对象,未找到返回null + */ public Task getChilTaskByGid(String gid) { for (Task task : mChildren) { if (task.getGid().equals(gid)) @@ -329,15 +412,29 @@ public class TaskList extends Node { return null; } + /** + * 获取所有子任务列表 + * @return 子任务列表 + */ public ArrayList getChildTaskList() { return this.mChildren; } + // 以下为属性的setter和getter方法 + + /** + * 设置任务列表的排序索引 + * @param index 排序索引 + */ public void setIndex(int index) { this.mIndex = index; } + /** + * 获取任务列表的排序索引 + * @return 排序索引 + */ public int getIndex() { return this.mIndex; } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/exception/ActionFailureException.java b/src/Notes-master/src/net/micode/notes/gtask/exception/ActionFailureException.java index 15504be..66a94cf 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/exception/ActionFailureException.java +++ b/src/Notes-master/src/net/micode/notes/gtask/exception/ActionFailureException.java @@ -2,32 +2,45 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ package net.micode.notes.gtask.exception; +/** + * 操作失败异常类 + * 用于表示任务同步、数据操作等过程中发生的不可恢复错误 + */ public class ActionFailureException extends RuntimeException { - private static final long serialVersionUID = 4425249765923293627L; + private static final long serialVersionUID = 4425249765923293627L; // 序列化版本号 + /** + * 无参构造函数 + */ public ActionFailureException() { super(); } + /** + * 带错误消息的构造函数 + * @param paramString 错误消息字符串 + */ public ActionFailureException(String paramString) { super(paramString); } + /** + * 带错误消息和原因的构造函数 + * @param paramString 错误消息字符串 + * @param paramThrowable 导致异常的根本原因 + */ public ActionFailureException(String paramString, Throwable paramThrowable) { super(paramString, paramThrowable); } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/exception/NetworkFailureException.java b/src/Notes-master/src/net/micode/notes/gtask/exception/NetworkFailureException.java index b08cfb1..9d7cd2c 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/exception/NetworkFailureException.java +++ b/src/Notes-master/src/net/micode/notes/gtask/exception/NetworkFailureException.java @@ -2,32 +2,46 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ package net.micode.notes.gtask.exception; +/** + * 网络失败异常类 + * 用于表示网络连接相关的异常(如超时、连接中断等) + */ public class NetworkFailureException extends Exception { - private static final long serialVersionUID = 2107610287180234136L; + private static final long serialVersionUID = 2107610287180234136L; // 序列化版本号,用于保持类版本兼容性 + /** + * 无参构造函数 + * 创建一个默认的网络失败异常对象 + */ public NetworkFailureException() { super(); } + /** + * 带错误消息的构造函数 + * @param paramString 描述异常原因的消息字符串 + */ public NetworkFailureException(String paramString) { super(paramString); } + /** + * 带错误消息和根源异常的构造函数 + * @param paramString 描述异常原因的消息字符串 + * @param paramThrowable 导致当前异常的根本异常对象 + */ public NetworkFailureException(String paramString, Throwable paramThrowable) { super(paramString, paramThrowable); } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java index b3b61e7..3d3edae 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java +++ b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java @@ -1,18 +1,14 @@ - /* * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ package net.micode.notes.gtask.remote; @@ -28,96 +24,154 @@ import net.micode.notes.R; import net.micode.notes.ui.NotesListActivity; import net.micode.notes.ui.NotesPreferenceActivity; - +/** + * 处理Google Tasks同步的异步任务类 + * 负责在后台执行同步操作,并通过通知和回调机制反馈状态 + */ public class GTaskASyncTask extends AsyncTask { + // 同步通知的唯一标识ID private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; + // 完成回调接口,用于通知同步结束 public interface OnCompleteListener { - void onComplete(); + void onComplete(); // 同步完成时的回调方法 } - private Context mContext; - - private NotificationManager mNotifiManager; - - private GTaskManager mTaskManager; - - private OnCompleteListener mOnCompleteListener; + private Context mContext; // 应用上下文 + private NotificationManager mNotifiManager; // 通知管理器 + private GTaskManager mTaskManager; // 任务管理实例 + private OnCompleteListener mOnCompleteListener; // 完成回调监听器 + /** + * 构造函数 + * @param context 应用上下文 + * @param listener 同步完成回调监听器 + */ public GTaskASyncTask(Context context, OnCompleteListener listener) { mContext = context; mOnCompleteListener = listener; - mNotifiManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); + // 获取系统通知服务 + mNotifiManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + // 获取任务管理单例 mTaskManager = GTaskManager.getInstance(); } + /** + * 取消同步操作 + */ public void cancelSync() { - mTaskManager.cancelSync(); + mTaskManager.cancelSync(); // 调用任务管理器的取消同步方法 } + /** + * 发布同步进度消息(支持字符串数组参数) + * @param message 进度消息内容 + */ public void publishProgess(String message) { - publishProgress(new String[] { - message - }); + publishProgress(new String[]{message}); // 调用父类方法发布进度 } + /** + * 显示同步状态通知 + * @param tickerId 通知标题的资源ID + * @param content 通知内容文本 + */ private void showNotification(int tickerId, String content) { - Notification notification = new Notification(R.drawable.notification, mContext - .getString(tickerId), System.currentTimeMillis()); - notification.defaults = Notification.DEFAULT_LIGHTS; - notification.flags = Notification.FLAG_AUTO_CANCEL; PendingIntent pendingIntent; + // 根据通知类型设置不同的点击跳转目标 if (tickerId != R.string.ticker_success) { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesPreferenceActivity.class), 0); - + // 非成功状态跳转到设置界面 + pendingIntent = PendingIntent.getActivity(mContext, 0, + new Intent(mContext, NotesPreferenceActivity.class), + PendingIntent.FLAG_IMMUTABLE); } else { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesListActivity.class), 0); + // 成功状态跳转到笔记列表界面 + pendingIntent = PendingIntent.getActivity(mContext, 0, + new Intent(mContext, NotesListActivity.class), + PendingIntent.FLAG_IMMUTABLE); } - notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, - pendingIntent); + // 构建通知对象 + Notification.Builder builder = new Notification.Builder(mContext) + .setAutoCancel(true) // 点击后自动清除通知 + .setContentTitle(mContext.getString(R.string.app_name)) // 应用名称作为标题 + .setContentText(content) // 通知内容 + .setContentIntent(pendingIntent) // 点击通知后的跳转意图 + .setWhen(System.currentTimeMillis()) // 通知时间 + .setOngoing(true); // 显示为进行中状态(不可滑动清除) + Notification notification = builder.getNotification(); + // 显示通知 mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); } + /** + * 后台执行同步操作的核心方法 + * @param unused 未使用的参数(继承自AsyncTask) + * @return 同步结果状态码(来自GTaskManager的定义) + */ @Override protected Integer doInBackground(Void... unused) { - publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity - .getSyncAccountName(mContext))); + // 发布登录进度消息(包含当前同步账户名) + publishProgess(mContext.getString(R.string.sync_progress_login, + NotesPreferenceActivity.getSyncAccountName(mContext))); + // 调用任务管理器的同步方法,传入上下文和当前任务实例 return mTaskManager.sync(mContext, this); } + /** + * 处理进度更新的回调方法(在主线程执行) + * @param progress 包含进度消息的字符串数组 + */ @Override protected void onProgressUpdate(String... progress) { + // 显示同步中通知 showNotification(R.string.ticker_syncing, progress[0]); + // 如果上下文是同步服务,发送广播通知进度 if (mContext instanceof GTaskSyncService) { ((GTaskSyncService) mContext).sendBroadcast(progress[0]); } } + /** + * 处理后台任务完成的回调方法(在主线程执行) + * @param result 同步结果状态码 + */ @Override protected void onPostExecute(Integer result) { - if (result == GTaskManager.STATE_SUCCESS) { - showNotification(R.string.ticker_success, mContext.getString( - R.string.success_sync_account, mTaskManager.getSyncAccount())); - NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); - } else if (result == GTaskManager.STATE_NETWORK_ERROR) { - showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network)); - } else if (result == GTaskManager.STATE_INTERNAL_ERROR) { - showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); - } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { - showNotification(R.string.ticker_cancel, mContext - .getString(R.string.error_sync_cancelled)); + String content; + int tickerId; + // 根据不同的同步结果显示对应的通知 + switch (result) { + case GTaskManager.STATE_SUCCESS: + tickerId = R.string.ticker_success; + content = mContext.getString(R.string.success_sync_account, + mTaskManager.getSyncAccount()); // 显示成功消息和账户名 + NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); // 记录最后同步时间 + break; + case GTaskManager.STATE_NETWORK_ERROR: + tickerId = R.string.ticker_fail; + content = mContext.getString(R.string.error_sync_network); // 网络错误消息 + break; + case GTaskManager.STATE_INTERNAL_ERROR: + tickerId = R.string.ticker_fail; + content = mContext.getString(R.string.error_sync_internal); // 内部错误消息 + break; + case GTaskManager.STATE_SYNC_CANCELLED: + tickerId = R.string.ticker_cancel; + content = mContext.getString(R.string.error_sync_cancelled); // 取消同步消息 + break; + default: + return; } + showNotification(tickerId, content); // 显示结果通知 + + // 在后台线程执行回调,避免阻塞主线程 if (mOnCompleteListener != null) { new Thread(new Runnable() { - public void run() { - mOnCompleteListener.onComplete(); + mOnCompleteListener.onComplete(); // 触发完成回调 } }).start(); } } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java index c67dfdf..7637e41 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java +++ b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java @@ -14,8 +14,10 @@ * limitations under the License. */ +// Google Tasks API客户端实现类,负责与Google Tasks服务通信 package net.micode.notes.gtask.remote; +// Android基础组件导入 import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AccountManagerFuture; @@ -24,6 +26,7 @@ import android.os.Bundle; import android.text.TextUtils; import android.util.Log; +// 项目内部类导入 import net.micode.notes.gtask.data.Node; import net.micode.notes.gtask.data.Task; import net.micode.notes.gtask.data.TaskList; @@ -32,6 +35,7 @@ import net.micode.notes.gtask.exception.NetworkFailureException; import net.micode.notes.tool.GTaskStringUtils; import net.micode.notes.ui.NotesPreferenceActivity; +// HTTP客户端和JSON处理类导入 import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; @@ -50,6 +54,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +// Java IO和工具类导入 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -60,36 +65,55 @@ import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; - +/** + * Google Tasks API客户端类,封装了与Google Tasks服务的所有交互 + */ public class GTaskClient { + // 日志标签 private static final String TAG = GTaskClient.class.getSimpleName(); + // Google Tasks基础URL private static final String GTASK_URL = "https://mail.google.com/tasks/"; + // Google Tasks获取数据URL private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; + // Google Tasks提交数据URL private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; + // 单例实例 private static GTaskClient mInstance = null; + // HTTP客户端 private DefaultHttpClient mHttpClient; + // 获取数据URL private String mGetUrl; + // 提交数据URL private String mPostUrl; + // 客户端版本号 private long mClientVersion; + // 登录状态标志 private boolean mLoggedin; + // 最后登录时间 private long mLastLoginTime; + // 操作ID计数器 private int mActionId; + // 关联的Google账户 private Account mAccount; + // 待更新操作数组 private JSONArray mUpdateArray; + /** + * 私有构造函数,初始化默认值 + */ private GTaskClient() { mHttpClient = null; mGetUrl = GTASK_GET_URL; @@ -102,6 +126,10 @@ public class GTaskClient { mUpdateArray = null; } + /** + * 获取单例实例 + * @return GTaskClient单例实例 + */ public static synchronized GTaskClient getInstance() { if (mInstance == null) { mInstance = new GTaskClient(); @@ -109,36 +137,43 @@ public class GTaskClient { return mInstance; } + /** + * 登录Google Tasks服务 + * @param activity 上下文Activity + * @return 是否登录成功 + */ public boolean login(Activity activity) { - // we suppose that the cookie would expire after 5 minutes - // then we need to re-login + // 假设cookie在5分钟后过期,需要重新登录 final long interval = 1000 * 60 * 5; if (mLastLoginTime + interval < System.currentTimeMillis()) { mLoggedin = false; } - // need to re-login after account switch - if (mLoggedin - && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity - .getSyncAccountName(activity))) { + // 账户切换后需要重新登录 + if (mLoggedin && !TextUtils.equals(getSyncAccount().name, + NotesPreferenceActivity.getSyncAccountName(activity))) { mLoggedin = false; } + // 如果已经登录则直接返回 if (mLoggedin) { Log.d(TAG, "already logged in"); return true; } + // 更新最后登录时间 mLastLoginTime = System.currentTimeMillis(); + + // 获取Google账户认证令牌 String authToken = loginGoogleAccount(activity, false); if (authToken == null) { Log.e(TAG, "login google account failed"); return false; } - // login with custom domain if necessary - if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() - .endsWith("googlemail.com"))) { + // 处理自定义域名的登录(非gmail.com或googlemail.com) + if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || + mAccount.name.toLowerCase().endsWith("googlemail.com"))) { StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); int index = mAccount.name.indexOf('@') + 1; String suffix = mAccount.name.substring(index); @@ -146,12 +181,13 @@ public class GTaskClient { mGetUrl = url.toString() + "ig"; mPostUrl = url.toString() + "r/ig"; + // 尝试使用自定义域名登录 if (tryToLoginGtask(activity, authToken)) { mLoggedin = true; } } - // try to login with google official url + // 如果自定义域名登录失败,尝试使用官方URL登录 if (!mLoggedin) { mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -164,16 +200,26 @@ public class GTaskClient { return true; } + /** + * 登录Google账户并获取认证令牌 + * @param activity 上下文Activity + * @param invalidateToken 是否使旧令牌失效 + * @return 认证令牌 + */ private String loginGoogleAccount(Activity activity, boolean invalidateToken) { String authToken; AccountManager accountManager = AccountManager.get(activity); + + // 获取所有Google账户 Account[] accounts = accountManager.getAccountsByType("com.google"); + // 检查是否有可用账户 if (accounts.length == 0) { Log.e(TAG, "there is no available google account"); return null; } + // 获取设置中指定的同步账户 String accountName = NotesPreferenceActivity.getSyncAccountName(activity); Account account = null; for (Account a : accounts) { @@ -182,6 +228,8 @@ public class GTaskClient { break; } } + + // 验证账户是否存在 if (account != null) { mAccount = account; } else { @@ -189,12 +237,14 @@ public class GTaskClient { return null; } - // get the token now + // 获取认证令牌 AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, "goanna_mobile", null, activity, null, null); try { Bundle authTokenBundle = accountManagerFuture.getResult(); authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); + + // 如果需要使旧令牌失效 if (invalidateToken) { accountManager.invalidateAuthToken("com.google", authToken); loginGoogleAccount(activity, false); @@ -207,16 +257,23 @@ public class GTaskClient { return authToken; } + /** + * 尝试登录Google Tasks服务 + * @param activity 上下文Activity + * @param authToken 认证令牌 + * @return 是否登录成功 + */ private boolean tryToLoginGtask(Activity activity, String authToken) { + // 第一次尝试登录 if (!loginGtask(authToken)) { - // maybe the auth token is out of date, now let's invalidate the - // token and try again + // 如果失败,可能是令牌过期,使旧令牌失效并获取新令牌 authToken = loginGoogleAccount(activity, true); if (authToken == null) { Log.e(TAG, "login google account failed"); return false; } + // 使用新令牌再次尝试登录 if (!loginGtask(authToken)) { Log.e(TAG, "login gtask failed"); return false; @@ -225,25 +282,33 @@ public class GTaskClient { return true; } + /** + * 实际执行Google Tasks登录操作 + * @param authToken 认证令牌 + * @return 是否登录成功 + */ private boolean loginGtask(String authToken) { + // 设置HTTP连接参数 int timeoutConnection = 10000; int timeoutSocket = 15000; HttpParams httpParameters = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); + + // 创建HTTP客户端 mHttpClient = new DefaultHttpClient(httpParameters); BasicCookieStore localBasicCookieStore = new BasicCookieStore(); mHttpClient.setCookieStore(localBasicCookieStore); HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); - // login gtask + // 执行登录请求 try { String loginUrl = mGetUrl + "?auth=" + authToken; HttpGet httpGet = new HttpGet(loginUrl); HttpResponse response = null; response = mHttpClient.execute(httpGet); - // get the cookie now + // 检查是否获取到认证cookie List cookies = mHttpClient.getCookieStore().getCookies(); boolean hasAuthCookie = false; for (Cookie cookie : cookies) { @@ -255,7 +320,7 @@ public class GTaskClient { Log.w(TAG, "it seems that there is no auth cookie"); } - // get the client version + // 从响应中提取客户端版本号 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -272,7 +337,6 @@ public class GTaskClient { e.printStackTrace(); return false; } catch (Exception e) { - // simply catch all exceptions Log.e(TAG, "httpget gtask_url failed"); return false; } @@ -280,10 +344,18 @@ public class GTaskClient { return true; } + /** + * 获取下一个操作ID + * @return 操作ID + */ private int getActionId() { return mActionId++; } + /** + * 创建HTTP POST请求 + * @return 配置好的HttpPost对象 + */ private HttpPost createHttpPost() { HttpPost httpPost = new HttpPost(mPostUrl); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); @@ -291,13 +363,21 @@ public class GTaskClient { return httpPost; } + /** + * 从HTTP实体获取响应内容 + * @param entity HTTP实体 + * @return 响应内容字符串 + * @throws IOException 如果读取失败 + */ private String getResponseContent(HttpEntity entity) throws IOException { + // 检查内容编码 String contentEncoding = null; if (entity.getContentEncoding() != null) { contentEncoding = entity.getContentEncoding().getValue(); Log.d(TAG, "encoding: " + contentEncoding); } + // 根据编码类型创建适当的输入流 InputStream input = entity.getContent(); if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { input = new GZIPInputStream(entity.getContent()); @@ -306,6 +386,7 @@ public class GTaskClient { input = new InflaterInputStream(entity.getContent(), inflater); } + // 读取响应内容 try { InputStreamReader isr = new InputStreamReader(input); BufferedReader br = new BufferedReader(isr); @@ -323,7 +404,14 @@ public class GTaskClient { } } + /** + * 发送POST请求 + * @param js 要发送的JSON对象 + * @return 响应JSON对象 + * @throws NetworkFailureException 网络错误时抛出 + */ private JSONObject postRequest(JSONObject js) throws NetworkFailureException { + // 检查登录状态 if (!mLoggedin) { Log.e(TAG, "please login first"); throw new ActionFailureException("not logged in"); @@ -331,12 +419,13 @@ public class GTaskClient { HttpPost httpPost = createHttpPost(); try { + // 准备请求参数 LinkedList list = new LinkedList(); list.add(new BasicNameValuePair("r", js.toString())); UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); httpPost.setEntity(entity); - // execute the post + // 执行请求并处理响应 HttpResponse response = mHttpClient.execute(httpPost); String jsString = getResponseContent(response.getEntity()); return new JSONObject(jsString); @@ -360,23 +449,31 @@ public class GTaskClient { } } + /** + * 创建任务 + * @param task 要创建的任务对象 + * @throws NetworkFailureException 网络错误时抛出 + */ public void createTask(Task task) throws NetworkFailureException { + // 提交所有待更新操作 commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); - // action_list + // 添加创建任务操作 actionList.put(task.getCreateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client_version + // 设置客户端版本 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - // post + // 发送请求并处理响应 JSONObject jsResponse = postRequest(jsPost); JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( GTaskStringUtils.GTASK_JSON_RESULTS).get(0); + + // 设置任务ID task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); } catch (JSONException e) { @@ -386,23 +483,31 @@ public class GTaskClient { } } + /** + * 创建任务列表 + * @param tasklist 要创建的任务列表对象 + * @throws NetworkFailureException 网络错误时抛出 + */ public void createTaskList(TaskList tasklist) throws NetworkFailureException { + // 提交所有待更新操作 commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); - // action_list + // 添加创建任务列表操作 actionList.put(tasklist.getCreateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client version + // 设置客户端版本 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - // post + // 发送请求并处理响应 JSONObject jsResponse = postRequest(jsPost); JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( GTaskStringUtils.GTASK_JSON_RESULTS).get(0); + + // 设置任务列表ID tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); } catch (JSONException e) { @@ -412,17 +517,22 @@ public class GTaskClient { } } + /** + * 提交所有待更新操作 + * @throws NetworkFailureException 网络错误时抛出 + */ public void commitUpdate() throws NetworkFailureException { if (mUpdateArray != null) { try { JSONObject jsPost = new JSONObject(); - // action_list + // 添加待更新操作列表 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); - // client_version + // 设置客户端版本 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + // 发送请求 postRequest(jsPost); mUpdateArray = null; } catch (JSONException e) { @@ -433,50 +543,67 @@ public class GTaskClient { } } + /** + * 添加待更新节点 + * @param node 要更新的节点 + * @throws NetworkFailureException 网络错误时抛出 + */ public void addUpdateNode(Node node) throws NetworkFailureException { if (node != null) { - // too many update items may result in an error - // set max to 10 items + // 如果待更新操作过多(超过10个),先提交 if (mUpdateArray != null && mUpdateArray.length() > 10) { commitUpdate(); } + // 初始化更新数组(如果为空) if (mUpdateArray == null) mUpdateArray = new JSONArray(); + + // 添加更新操作 mUpdateArray.put(node.getUpdateAction(getActionId())); } } + /** + * 移动任务 + * @param task 要移动的任务 + * @param preParent 原父任务列表 + * @param curParent 新父任务列表 + * @throws NetworkFailureException 网络错误时抛出 + */ public void moveTask(Task task, TaskList preParent, TaskList curParent) throws NetworkFailureException { + // 提交所有待更新操作 commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); JSONObject action = new JSONObject(); - // action_list + // 设置移动操作参数 action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); + + // 如果在同一任务列表中移动且有前驱兄弟节点 if (preParent == curParent && task.getPriorSibling() != null) { - // put prioring_sibing_id only if moving within the tasklist and - // it is not the first one action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); } + + // 设置源列表和目标父节点 action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); + + // 如果是在不同任务列表间移动 if (preParent != curParent) { - // put the dest_list only if moving between tasklists action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); } + + // 添加操作并发送请求 actionList.put(action); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client_version jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - postRequest(jsPost); } catch (JSONException e) { @@ -486,20 +613,25 @@ public class GTaskClient { } } + /** + * 删除节点 + * @param node 要删除的节点 + * @throws NetworkFailureException 网络错误时抛出 + */ public void deleteNode(Node node) throws NetworkFailureException { + // 提交所有待更新操作 commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); - // action_list + // 标记节点为已删除并添加更新操作 node.setDeleted(true); actionList.put(node.getUpdateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - // client_version + // 设置客户端版本并发送请求 jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); - postRequest(jsPost); mUpdateArray = null; } catch (JSONException e) { @@ -509,18 +641,25 @@ public class GTaskClient { } } + /** + * 获取所有任务列表 + * @return 任务列表JSON数组 + * @throws NetworkFailureException 网络错误时抛出 + */ public JSONArray getTaskLists() throws NetworkFailureException { + // 检查登录状态 if (!mLoggedin) { Log.e(TAG, "please login first"); throw new ActionFailureException("not logged in"); } try { + // 发送GET请求获取任务列表 HttpGet httpGet = new HttpGet(mGetUrl); HttpResponse response = null; response = mHttpClient.execute(httpGet); - // get the task list + // 从响应中提取任务列表数据 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -547,25 +686,33 @@ public class GTaskClient { } } + /** + * 获取指定任务列表的所有任务 + * @param listGid 任务列表ID + * @return 任务JSON数组 + * @throws NetworkFailureException 网络错误时抛出 + */ public JSONArray getTaskList(String listGid) throws NetworkFailureException { + // 提交所有待更新操作 commitUpdate(); try { JSONObject jsPost = new JSONObject(); JSONArray actionList = new JSONArray(); JSONObject action = new JSONObject(); - // action_list + // 设置获取所有任务操作参数 action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); + + // 添加操作并发送请求 actionList.put(action); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); - - // client_version jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + // 处理响应 JSONObject jsResponse = postRequest(jsPost); return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); } catch (JSONException e) { @@ -575,11 +722,18 @@ public class GTaskClient { } } + /** + * 获取同步账户 + * @return 同步账户对象 + */ public Account getSyncAccount() { return mAccount; } + /** + * 重置待更新数组 + */ public void resetUpdateArray() { mUpdateArray = null; } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java index d2b4082..a312c03 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java +++ b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java @@ -14,8 +14,10 @@ * limitations under the License. */ +// Google Tasks同步管理类,负责本地便签与Google Tasks的同步操作 package net.micode.notes.gtask.remote; +// Android基础组件导入 import android.app.Activity; import android.content.ContentResolver; import android.content.ContentUris; @@ -24,7 +26,10 @@ import android.content.Context; import android.database.Cursor; import android.util.Log; +// 项目资源文件导入 import net.micode.notes.R; + +// 数据模型和工具类导入 import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.NoteColumns; @@ -38,88 +43,125 @@ import net.micode.notes.gtask.exception.NetworkFailureException; import net.micode.notes.tool.DataUtils; import net.micode.notes.tool.GTaskStringUtils; +// JSON处理类导入 import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +// Java集合类导入 import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; - +// Google Tasks同步管理主类 public class GTaskManager { + // 日志标签 private static final String TAG = GTaskManager.class.getSimpleName(); + // 同步状态常量定义 public static final int STATE_SUCCESS = 0; - public static final int STATE_NETWORK_ERROR = 1; - public static final int STATE_INTERNAL_ERROR = 2; - public static final int STATE_SYNC_IN_PROGRESS = 3; - public static final int STATE_SYNC_CANCELLED = 4; + // 单例实例 private static GTaskManager mInstance = null; + // Activity上下文 private Activity mActivity; + // 应用上下文 private Context mContext; + // 内容解析器 private ContentResolver mContentResolver; + // 同步状态标志 private boolean mSyncing; + // 取消同步标志 private boolean mCancelled; + // 任务列表哈希表(gid -> TaskList) private HashMap mGTaskListHashMap; + // 任务节点哈希表(gid -> Node) private HashMap mGTaskHashMap; + // 元数据哈希表(gid -> MetaData) private HashMap mMetaHashMap; + // 元数据任务列表 private TaskList mMetaList; + // 本地删除ID集合 private HashSet mLocalDeleteIdMap; + // Google任务ID到本地ID的映射 private HashMap mGidToNid; + // 本地ID到Google任务ID的映射 private HashMap mNidToGid; + // 私有构造函数 private GTaskManager() { + // 初始化同步状态标志 mSyncing = false; mCancelled = false; + + // 初始化任务列表哈希表 mGTaskListHashMap = new HashMap(); + + // 初始化任务节点哈希表 mGTaskHashMap = new HashMap(); + + // 初始化元数据哈希表 mMetaHashMap = new HashMap(); + + // 初始化元数据任务列表 mMetaList = null; + + // 初始化本地删除ID集合 mLocalDeleteIdMap = new HashSet(); + + // 初始化ID映射表 mGidToNid = new HashMap(); mNidToGid = new HashMap(); } + // 获取单例实例 public static synchronized GTaskManager getInstance() { + // 如果实例不存在则创建新实例 if (mInstance == null) { mInstance = new GTaskManager(); } return mInstance; } + // 设置Activity上下文(用于获取认证令牌) public synchronized void setActivityContext(Activity activity) { - // used for getting authtoken mActivity = activity; } + // 执行同步操作 public int sync(Context context, GTaskASyncTask asyncTask) { + // 检查是否正在同步 if (mSyncing) { Log.d(TAG, "Sync is in progress"); return STATE_SYNC_IN_PROGRESS; } + + // 初始化上下文和内容解析器 mContext = context; mContentResolver = mContext.getContentResolver(); + + // 设置同步状态标志 mSyncing = true; mCancelled = false; + + // 清空各种缓存和映射表 mGTaskListHashMap.clear(); mGTaskHashMap.clear(); mMetaHashMap.clear(); @@ -128,34 +170,39 @@ public class GTaskManager { mNidToGid.clear(); try { + // 获取GTask客户端实例 GTaskClient client = GTaskClient.getInstance(); client.resetUpdateArray(); - // login google task + // 登录Google Tasks(如果未取消) if (!mCancelled) { if (!client.login(mActivity)) { throw new NetworkFailureException("login google task failed"); } } - // get the task list from google + // 初始化任务列表 asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); initGTaskList(); - // do content sync work + // 执行内容同步 asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); syncContent(); } catch (NetworkFailureException e) { + // 处理网络错误 Log.e(TAG, e.toString()); return STATE_NETWORK_ERROR; } catch (ActionFailureException e) { + // 处理操作错误 Log.e(TAG, e.toString()); return STATE_INTERNAL_ERROR; } catch (Exception e) { + // 处理其他异常 Log.e(TAG, e.toString()); e.printStackTrace(); return STATE_INTERNAL_ERROR; } finally { + // 清理资源 mGTaskListHashMap.clear(); mGTaskHashMap.clear(); mMetaHashMap.clear(); @@ -165,29 +212,37 @@ public class GTaskManager { mSyncing = false; } + // 返回同步结果状态 return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; } + // 初始化Google Tasks列表 private void initGTaskList() throws NetworkFailureException { + // 检查是否已取消 if (mCancelled) return; + + // 获取GTask客户端实例 GTaskClient client = GTaskClient.getInstance(); try { + // 获取任务列表JSON数组 JSONArray jsTaskLists = client.getTaskLists(); - // init meta list first + // 首先初始化元数据列表 mMetaList = null; for (int i = 0; i < jsTaskLists.length(); i++) { + // 获取任务列表JSON对象 JSONObject object = jsTaskLists.getJSONObject(i); String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); - if (name - .equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { + // 检查是否为元数据文件夹 + if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { + // 创建元数据任务列表 mMetaList = new TaskList(); mMetaList.setContentByRemoteJSON(object); - // load meta data + // 加载元数据 JSONArray jsMetas = client.getTaskList(gid); for (int j = 0; j < jsMetas.length(); j++) { object = (JSONObject) jsMetas.getJSONObject(j); @@ -203,7 +258,7 @@ public class GTaskManager { } } - // create meta list if not existed + // 如果元数据列表不存在则创建 if (mMetaList == null) { mMetaList = new TaskList(); mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX @@ -211,21 +266,23 @@ public class GTaskManager { GTaskClient.getInstance().createTaskList(mMetaList); } - // init task list + // 初始化普通任务列表 for (int i = 0; i < jsTaskLists.length(); i++) { JSONObject object = jsTaskLists.getJSONObject(i); String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); + // 检查是否为MIUI文件夹(非元数据文件夹) if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX) && !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META)) { + + GTaskStringUtils.FOLDER_META)) { + // 创建任务列表并添加到哈希表 TaskList tasklist = new TaskList(); tasklist.setContentByRemoteJSON(object); mGTaskListHashMap.put(gid, tasklist); mGTaskHashMap.put(gid, tasklist); - // load tasks + // 加载任务列表中的任务 JSONArray jsTasks = client.getTaskList(gid); for (int j = 0; j < jsTasks.length(); j++) { object = (JSONObject) jsTasks.getJSONObject(j); @@ -241,78 +298,91 @@ public class GTaskManager { } } } catch (JSONException e) { + // 处理JSON解析错误 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("initGTaskList: handing JSONObject failed"); } } + // 同步内容数据 private void syncContent() throws NetworkFailureException { + // 同步类型和临时变量 int syncType; Cursor c = null; String gid; Node node; + // 清空本地删除ID集合 mLocalDeleteIdMap.clear(); + // 检查是否已取消 if (mCancelled) { return; } - // for local deleted note + // 处理本地已删除的便签 try { + // 查询回收站中的便签 c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type<>? AND parent_id=?)", new String[] { String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) }, null); if (c != null) { while (c.moveToNext()) { + // 获取Google任务ID和对应节点 gid = c.getString(SqlNote.GTASK_ID_COLUMN); node = mGTaskHashMap.get(gid); if (node != null) { + // 从哈希表中移除并执行同步 mGTaskHashMap.remove(gid); doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c); } + // 添加到本地删除集合 mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); } } else { Log.w(TAG, "failed to query trash folder"); } } finally { + // 关闭Cursor if (c != null) { c.close(); c = null; } } - // sync folder first + // 首先同步文件夹 syncFolder(); - // for note existing in database + // 处理数据库中存在的便签 try { + // 查询非回收站中的便签 c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type=? AND parent_id<>?)", new String[] { String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER) }, NoteColumns.TYPE + " DESC"); if (c != null) { while (c.moveToNext()) { + // 获取Google任务ID和对应节点 gid = c.getString(SqlNote.GTASK_ID_COLUMN); node = mGTaskHashMap.get(gid); if (node != null) { + // 从哈希表中移除并确定同步类型 mGTaskHashMap.remove(gid); mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); syncType = node.getSyncAction(c); } else { + // 根据情况确定是本地添加还是远程删除 if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add syncType = Node.SYNC_ACTION_ADD_REMOTE; } else { - // remote delete syncType = Node.SYNC_ACTION_DEL_LOCAL; } } + // 执行内容同步 doContentSync(syncType, node, c); } } else { @@ -320,13 +390,14 @@ public class GTaskManager { } } finally { + // 关闭Cursor if (c != null) { c.close(); c = null; } } - // go through remaining items + // 处理剩余的项目(远程添加) Iterator> iter = mGTaskHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -334,46 +405,50 @@ public class GTaskManager { doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); } - // mCancelled can be set by another thread, so we neet to check one by - // one - // clear local delete table + // 检查是否已取消(可能由其他线程设置) + // 清理本地删除表 if (!mCancelled) { if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { throw new ActionFailureException("failed to batch-delete local deleted notes"); } } - // refresh local sync id + // 刷新本地同步ID(如果未取消) if (!mCancelled) { GTaskClient.getInstance().commitUpdate(); refreshLocalSyncId(); } - } + // 同步文件夹 private void syncFolder() throws NetworkFailureException { + // 临时变量 Cursor c = null; String gid; Node node; int syncType; + // 检查是否已取消 if (mCancelled) { return; } - // for root folder + // 处理根文件夹 try { + // 查询根文件夹 c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); if (c != null) { c.moveToNext(); + // 获取Google任务ID和对应节点 gid = c.getString(SqlNote.GTASK_ID_COLUMN); node = mGTaskHashMap.get(gid); if (node != null) { + // 从哈希表中移除并更新映射 mGTaskHashMap.remove(gid); mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER); mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid); - // for system folder, only update remote name if necessary + // 对于系统文件夹,只在必要时更新远程名称 if (!node.getName().equals( GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); @@ -384,28 +459,31 @@ public class GTaskManager { Log.w(TAG, "failed to query root folder"); } } finally { + // 关闭Cursor if (c != null) { c.close(); c = null; } } - // for call-note folder + // 处理通话记录文件夹 try { + // 查询通话记录文件夹 c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", new String[] { - String.valueOf(Notes.ID_CALL_RECORD_FOLDER) + String.valueOf(Notes.ID_CALL_RECORD_FOLDER) }, null); if (c != null) { if (c.moveToNext()) { + // 获取Google任务ID和对应节点 gid = c.getString(SqlNote.GTASK_ID_COLUMN); node = mGTaskHashMap.get(gid); if (node != null) { + // 从哈希表中移除并更新映射 mGTaskHashMap.remove(gid); mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER); mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid); - // for system folder, only update remote name if - // necessary + // 对于系统文件夹,只在必要时更新远程名称 if (!node.getName().equals( GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) @@ -418,49 +496,54 @@ public class GTaskManager { Log.w(TAG, "failed to query call note folder"); } } finally { + // 关闭Cursor if (c != null) { c.close(); c = null; } } - // for local existing folders + // 处理本地存在的文件夹 try { + // 查询非回收站中的文件夹 c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type=? AND parent_id<>?)", new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER) }, NoteColumns.TYPE + " DESC"); if (c != null) { while (c.moveToNext()) { + // 获取Google任务ID和对应节点 gid = c.getString(SqlNote.GTASK_ID_COLUMN); node = mGTaskHashMap.get(gid); if (node != null) { + // 从哈希表中移除并确定同步类型 mGTaskHashMap.remove(gid); mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); syncType = node.getSyncAction(c); } else { + // 根据情况确定是本地添加还是远程删除 if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add syncType = Node.SYNC_ACTION_ADD_REMOTE; } else { - // remote delete syncType = Node.SYNC_ACTION_DEL_LOCAL; } } + // 执行内容同步 doContentSync(syncType, node, c); } } else { Log.w(TAG, "failed to query existing folder"); } } finally { + // 关闭Cursor if (c != null) { c.close(); c = null; } } - // for remote add folders + // 处理远程添加的文件夹 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -472,24 +555,33 @@ public class GTaskManager { } } + // 如果未取消则提交更新 if (!mCancelled) GTaskClient.getInstance().commitUpdate(); } + // 执行具体的内容同步操作 private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { + // 检查是否已取消 if (mCancelled) { return; } + // 元数据临时变量 MetaData meta; + + // 根据同步类型执行不同操作 switch (syncType) { case Node.SYNC_ACTION_ADD_LOCAL: + // 本地添加节点 addLocalNode(node); break; case Node.SYNC_ACTION_ADD_REMOTE: + // 远程添加节点 addRemoteNode(node, c); break; case Node.SYNC_ACTION_DEL_LOCAL: + // 本地删除节点 meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN)); if (meta != null) { GTaskClient.getInstance().deleteNode(meta); @@ -497,6 +589,7 @@ public class GTaskManager { mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); break; case Node.SYNC_ACTION_DEL_REMOTE: + // 远程删除节点 meta = mMetaHashMap.get(node.getGid()); if (meta != null) { GTaskClient.getInstance().deleteNode(meta); @@ -504,57 +597,70 @@ public class GTaskManager { GTaskClient.getInstance().deleteNode(node); break; case Node.SYNC_ACTION_UPDATE_LOCAL: + // 更新本地节点 updateLocalNode(node, c); break; case Node.SYNC_ACTION_UPDATE_REMOTE: + // 更新远程节点 updateRemoteNode(node, c); break; case Node.SYNC_ACTION_UPDATE_CONFLICT: - // merging both modifications maybe a good idea - // right now just use local update simply + // 更新冲突(目前简单使用本地更新) updateRemoteNode(node, c); break; case Node.SYNC_ACTION_NONE: + // 无操作 break; case Node.SYNC_ACTION_ERROR: default: + // 未知操作类型错误 throw new ActionFailureException("unkown sync action type"); } } + // 添加本地节点 private void addLocalNode(Node node) throws NetworkFailureException { + // 检查是否已取消 if (mCancelled) { return; } + // 创建SQLite便签对象 SqlNote sqlNote; if (node instanceof TaskList) { + // 处理任务列表(文件夹) if (node.getName().equals( GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) { + // 根文件夹 sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER); } else if (node.getName().equals( GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { + // 通话记录文件夹 sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER); } else { + // 普通文件夹 sqlNote = new SqlNote(mContext); sqlNote.setContent(node.getLocalJSONFromContent()); sqlNote.setParentId(Notes.ID_ROOT_FOLDER); } } else { + // 处理普通便签 sqlNote = new SqlNote(mContext); JSONObject js = node.getLocalJSONFromContent(); try { + // 处理便签ID冲突 if (js.has(GTaskStringUtils.META_HEAD_NOTE)) { JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); if (note.has(NoteColumns.ID)) { long id = note.getLong(NoteColumns.ID); if (DataUtils.existInNoteDatabase(mContentResolver, id)) { - // the id is not available, have to create a new one + // ID不可用,需要创建新ID note.remove(NoteColumns.ID); } } } + // 处理数据ID冲突 if (js.has(GTaskStringUtils.META_HEAD_DATA)) { JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); for (int i = 0; i < dataArray.length(); i++) { @@ -562,13 +668,11 @@ public class GTaskManager { if (data.has(DataColumns.ID)) { long dataId = data.getLong(DataColumns.ID); if (DataUtils.existInDataDatabase(mContentResolver, dataId)) { - // the data id is not available, have to create - // a new one + // 数据ID不可用,需要创建新ID data.remove(DataColumns.ID); } } } - } } catch (JSONException e) { Log.w(TAG, e.toString()); @@ -576,6 +680,7 @@ public class GTaskManager { } sqlNote.setContent(js); + // 设置父节点ID Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); if (parentId == null) { Log.e(TAG, "cannot find task's parent id locally"); @@ -584,28 +689,32 @@ public class GTaskManager { sqlNote.setParentId(parentId.longValue()); } - // create the local node + // 创建本地节点 sqlNote.setGtaskId(node.getGid()); sqlNote.commit(false); - // update gid-nid mapping + // 更新gid-nid映射 mGidToNid.put(node.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), node.getGid()); - // update meta + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); } + // 更新本地节点 private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { + // 检查是否已取消 if (mCancelled) { return; } + // 创建SQLite便签对象 SqlNote sqlNote; - // update the note locally + // 更新本地便签 sqlNote = new SqlNote(mContext, c); sqlNote.setContent(node.getLocalJSONFromContent()); + // 设置父节点ID Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()) : new Long(Notes.ID_ROOT_FOLDER); if (parentId == null) { @@ -615,23 +724,28 @@ public class GTaskManager { sqlNote.setParentId(parentId.longValue()); sqlNote.commit(true); - // update meta info + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); } + // 添加远程节点 private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { + // 检查是否已取消 if (mCancelled) { return; } + // 创建SQLite便签对象 SqlNote sqlNote = new SqlNote(mContext, c); Node n; - // update remotely + // 远程更新 if (sqlNote.isNoteType()) { + // 处理普通便签 Task task = new Task(); task.setContentByLocalJSON(sqlNote.getContent()); + // 设置父任务列表 String parentGid = mNidToGid.get(sqlNote.getParentId()); if (parentGid == null) { Log.e(TAG, "cannot find task's parent tasklist"); @@ -639,15 +753,17 @@ public class GTaskManager { } mGTaskListHashMap.get(parentGid).addChildTask(task); + // 创建远程任务 GTaskClient.getInstance().createTask(task); n = (Node) task; - // add meta + // 添加元数据 updateRemoteMeta(task.getGid(), sqlNote); } else { + // 处理文件夹 TaskList tasklist = null; - // we need to skip folder if it has already existed + // 构建文件夹名称 String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX; if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) folderName += GTaskStringUtils.FOLDER_DEFAULT; @@ -656,6 +772,7 @@ public class GTaskManager { else folderName += sqlNote.getSnippet(); + // 检查是否已存在同名文件夹 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -671,7 +788,7 @@ public class GTaskManager { } } - // no match we can add now + // 如果没有匹配则创建新文件夹 if (tasklist == null) { tasklist = new TaskList(); tasklist.setContentByLocalJSON(sqlNote.getContent()); @@ -681,36 +798,40 @@ public class GTaskManager { n = (Node) tasklist; } - // update local note + // 更新本地便签 sqlNote.setGtaskId(n.getGid()); sqlNote.commit(false); sqlNote.resetLocalModified(); sqlNote.commit(true); - // gid-id mapping + // 更新gid-id映射 mGidToNid.put(n.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), n.getGid()); } + // 更新远程节点 private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { + // 检查是否已取消 if (mCancelled) { return; } + // 创建SQLite便签对象 SqlNote sqlNote = new SqlNote(mContext, c); - // update remotely + // 远程更新 node.setContentByLocalJSON(sqlNote.getContent()); GTaskClient.getInstance().addUpdateNode(node); - // update meta + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); - // move task if necessary + // 如果需要则移动任务 if (sqlNote.isNoteType()) { Task task = (Task) node; TaskList preParentList = task.getParent(); + // 获取当前父任务列表 String curParentGid = mNidToGid.get(sqlNote.getParentId()); if (curParentGid == null) { Log.e(TAG, "cannot find task's parent tasklist"); @@ -718,6 +839,7 @@ public class GTaskManager { } TaskList curParentList = mGTaskListHashMap.get(curParentGid); + // 如果父任务列表发生变化则移动任务 if (preParentList != curParentList) { preParentList.removeChildTask(task); curParentList.addChildTask(task); @@ -725,18 +847,23 @@ public class GTaskManager { } } - // clear local modified flag + // 清除本地修改标志 sqlNote.resetLocalModified(); sqlNote.commit(true); } + // 更新远程元数据 private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { + // 只处理普通便签的元数据 if (sqlNote != null && sqlNote.isNoteType()) { + // 获取或创建元数据 MetaData metaData = mMetaHashMap.get(gid); if (metaData != null) { + // 更新现有元数据 metaData.setMeta(gid, sqlNote.getContent()); GTaskClient.getInstance().addUpdateNode(metaData); } else { + // 创建新元数据 metaData = new MetaData(); metaData.setMeta(gid, sqlNote.getContent()); mMetaList.addChildTask(metaData); @@ -746,17 +873,20 @@ public class GTaskManager { } } + // 刷新本地同步ID private void refreshLocalSyncId() throws NetworkFailureException { + // 检查是否已取消 if (mCancelled) { return; } - // get the latest gtask list + // 获取最新的Google任务列表 mGTaskHashMap.clear(); mGTaskListHashMap.clear(); mMetaHashMap.clear(); initGTaskList(); + // 查询并更新本地同步ID Cursor c = null; try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, @@ -765,9 +895,11 @@ public class GTaskManager { }, NoteColumns.TYPE + " DESC"); if (c != null) { while (c.moveToNext()) { + // 获取Google任务ID和对应节点 String gid = c.getString(SqlNote.GTASK_ID_COLUMN); Node node = mGTaskHashMap.get(gid); if (node != null) { + // 从哈希表中移除并更新同步ID mGTaskHashMap.remove(gid); ContentValues values = new ContentValues(); values.put(NoteColumns.SYNC_ID, node.getLastModified()); @@ -783,6 +915,7 @@ public class GTaskManager { Log.w(TAG, "failed to query local note to refresh sync id"); } } finally { + // 关闭Cursor if (c != null) { c.close(); c = null; @@ -790,11 +923,13 @@ public class GTaskManager { } } + // 获取同步账户名称 public String getSyncAccount() { return GTaskClient.getInstance().getSyncAccount().name; } + // 取消同步操作 public void cancelSync() { mCancelled = true; } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java index cca36f7..af41346 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java +++ b/src/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java @@ -2,127 +2,192 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ -package net.micode.notes.gtask.remote; +package net.micode.notes.gtask.remote; // 指定代码所属的包名 -import android.app.Activity; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; +import android.app.Activity; // 导入Activity类,用于获取上下文 +import android.app.Service; // 导入Service类,用于创建后台服务 +import android.content.Context; // 导入Context类,提供应用环境信息 +import android.content.Intent; // 导入Intent类,用于组件间通信 +import android.os.Bundle; // 导入Bundle类,用于传递数据 +import android.os.IBinder; // 导入IBinder接口,用于服务间通信 +/** + * Google Tasks同步服务类,负责在后台执行任务同步操作 + * 通过Service机制实现,支持启动、取消同步等操作,并通过广播通知同步状态 + */ public class GTaskSyncService extends Service { + // 同步动作类型的Extra键名 public final static String ACTION_STRING_NAME = "sync_action_type"; + // 启动同步的动作类型常量 public final static int ACTION_START_SYNC = 0; + // 取消同步的动作类型常量 public final static int ACTION_CANCEL_SYNC = 1; + // 无效动作的类型常量 public final static int ACTION_INVALID = 2; + // 同步服务广播的名称,用于发送同步状态更新 public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service"; + // 广播中表示是否正在同步的Extra键名 public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing"; + // 广播中表示同步进度消息的Extra键名 public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg"; + // 静态变量,保存当前执行同步的异步任务实例 private static GTaskASyncTask mSyncTask = null; + // 静态变量,保存当前同步进度消息 private static String mSyncProgress = ""; + /** + * 启动Google Tasks同步操作 + * 检查是否已有同步任务在运行,若无则创建并执行新的同步任务 + */ private void startSync() { - if (mSyncTask == null) { + if (mSyncTask == null) { // 检查是否已有同步任务在运行 + // 创建新的异步同步任务实例,传入服务上下文和完成监听器 mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { + @Override public void onComplete() { - mSyncTask = null; - sendBroadcast(""); - stopSelf(); + mSyncTask = null; // 同步完成后将任务实例置为null + sendBroadcast(""); // 发送同步完成的广播 + stopSelf(); // 停止当前服务 } }); - sendBroadcast(""); - mSyncTask.execute(); + sendBroadcast(""); // 发送开始同步的广播 + mSyncTask.execute(); // 执行异步同步任务 } } + /** + * 取消正在进行的同步操作 + * 如果有同步任务正在运行,则调用其取消方法 + */ private void cancelSync() { - if (mSyncTask != null) { - mSyncTask.cancelSync(); + if (mSyncTask != null) { // 检查是否有同步任务在运行 + mSyncTask.cancelSync(); // 调用任务的取消方法 } } + /** + * 服务创建时调用的方法 + * 初始化服务状态,将同步任务实例置为null + */ @Override public void onCreate() { - mSyncTask = null; + mSyncTask = null; // 确保服务创建时没有残留的同步任务 } + /** + * 处理启动服务的命令 + * 根据Intent中携带的动作类型,执行相应的同步操作 + * @param intent 启动服务的Intent,可能包含同步动作类型 + * @param flags 启动标志 + * @param startId 启动ID + * @return 服务启动模式,此处返回START_STICKY表示服务被终止后会自动重启 + */ @Override public int onStartCommand(Intent intent, int flags, int startId) { - Bundle bundle = intent.getExtras(); - if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { - switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) { - case ACTION_START_SYNC: - startSync(); + Bundle bundle = intent.getExtras(); // 获取Intent携带的额外数据 + if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { // 检查是否包含动作类型 + switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) { // 获取动作类型并处理 + case ACTION_START_SYNC: // 启动同步动作 + startSync(); // 调用启动同步方法 break; - case ACTION_CANCEL_SYNC: - cancelSync(); + case ACTION_CANCEL_SYNC: // 取消同步动作 + cancelSync(); // 调用取消同步方法 break; - default: + default: // 无效动作类型 break; } - return START_STICKY; + return START_STICKY; // 返回START_STICKY表示服务被终止后会自动重启 } - return super.onStartCommand(intent, flags, startId); + return super.onStartCommand(intent, flags, startId); // 处理默认情况 } + /** + * 系统内存不足时调用的方法 + * 取消正在进行的同步任务,释放资源 + */ @Override public void onLowMemory() { - if (mSyncTask != null) { - mSyncTask.cancelSync(); + if (mSyncTask != null) { // 检查是否有同步任务在运行 + mSyncTask.cancelSync(); // 取消同步任务以释放资源 } } + /** + * 绑定服务时调用的方法 + * 由于本服务不支持绑定,返回null + * @param intent 绑定意图 + * @return null,表示不支持绑定 + */ public IBinder onBind(Intent intent) { - return null; + return null; // 本服务不支持绑定,返回null } + /** + * 发送同步状态广播 + * 将同步进度消息封装到Intent中并发送广播 + * @param msg 同步进度消息 + */ public void sendBroadcast(String msg) { - mSyncProgress = msg; - Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); - intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); - intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); - sendBroadcast(intent); + mSyncProgress = msg; // 更新同步进度消息 + Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); // 创建广播Intent + intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); // 添加是否正在同步的状态 + intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); // 添加同步进度消息 + sendBroadcast(intent); // 发送广播 } + /** + * 静态方法:启动Google Tasks同步服务 + * 从Activity上下文启动同步服务并传递启动同步的动作类型 + * @param activity 调用此方法的Activity,提供上下文 + */ public static void startSync(Activity activity) { - GTaskManager.getInstance().setActivityContext(activity); - Intent intent = new Intent(activity, GTaskSyncService.class); - intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC); - activity.startService(intent); + GTaskManager.getInstance().setActivityContext(activity); // 设置GTaskManager的Activity上下文 + Intent intent = new Intent(activity, GTaskSyncService.class); // 创建启动服务的Intent + intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC); // 添加启动同步的动作类型 + activity.startService(intent); // 启动服务 } + /** + * 静态方法:取消Google Tasks同步服务 + * 从上下文启动服务并传递取消同步的动作类型 + * @param context 调用此方法的上下文 + */ public static void cancelSync(Context context) { - Intent intent = new Intent(context, GTaskSyncService.class); - intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); - context.startService(intent); + Intent intent = new Intent(context, GTaskSyncService.class); // 创建启动服务的Intent + intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); // 添加取消同步的动作类型 + context.startService(intent); // 启动服务 } + /** + * 静态方法:检查是否正在进行同步 + * @return true表示正在同步,false表示未同步 + */ public static boolean isSyncing() { - return mSyncTask != null; + return mSyncTask != null; // 通过检查同步任务实例是否存在判断是否正在同步 } + /** + * 静态方法:获取当前同步进度消息 + * @return 当前同步进度消息字符串 + */ public static String getProgressString() { - return mSyncProgress; + return mSyncProgress; // 返回当前同步进度消息 } -} +} \ No newline at end of file From 06ce2ef0ccc1da756697b582bd09802feef78b3e Mon Sep 17 00:00:00 2001 From: Wang-YYu-Lu <1756892659@qq.com> Date: Tue, 27 May 2025 09:27:02 +0800 Subject: [PATCH 09/11] =?UTF-8?q?tool=E4=BB=A3=E7=A0=81=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/micode/notes/tool/BackupUtils.java | 401 ++++++++-------- .../src/net/micode/notes/tool/DataUtils.java | 429 +++++++++++------- .../micode/notes/tool/GTaskStringUtils.java | 112 ++--- .../net/micode/notes/tool/ResourceParser.java | 252 ++++++---- 4 files changed, 711 insertions(+), 483 deletions(-) diff --git a/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java b/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java index 39f6ec4..3932b45 100644 --- a/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/BackupUtils.java @@ -2,234 +2,277 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ -package net.micode.notes.tool; - -import android.content.Context; -import android.database.Cursor; -import android.os.Environment; -import android.text.TextUtils; -import android.text.format.DateFormat; -import android.util.Log; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; - - +package net.micode.notes.tool; // 指定代码所属的包名 + +import android.content.Context; // 导入Context类,提供应用环境信息 +import android.database.Cursor; // 导入Cursor类,用于查询数据库结果集 +import android.os.Environment; // 导入Environment类,获取外部存储信息 +import android.text.TextUtils; // 导入TextUtils类,提供文本处理工具 +import android.text.format.DateFormat; // 导入DateFormat类,用于日期格式化 +import android.util.Log; // 导入Log类,用于日志记录 + +import net.micode.notes.R; // 导入R资源类,访问应用资源 +import net.micode.notes.data.Notes; // 导入Notes类,访问笔记数据结构 +import net.micode.notes.data.Notes.DataColumns; // 导入笔记数据列定义 +import net.micode.notes.data.Notes.DataConstants; // 导入笔记数据常量 +import net.micode.notes.data.Notes.NoteColumns; // 导入笔记列定义 + +import java.io.File; // 导入File类,用于文件操作 +import java.io.FileNotFoundException; // 导入文件未找到异常类 +import java.io.FileOutputStream; // 导入文件输出流类 +import java.io.IOException; // 导入IO异常类 +import java.io.PrintStream; // 导入打印流类,用于文本输出 + +/** + * 备份工具类,用于将笔记数据导出为文本文件 + * 支持导出到SD卡,提供备份状态反馈和文件管理功能 + */ public class BackupUtils { - private static final String TAG = "BackupUtils"; - // Singleton stuff + private static final String TAG = "BackupUtils"; // 日志标签 + // 单例模式实现 private static BackupUtils sInstance; + /** + * 获取BackupUtils的单例实例 + * @param context 应用上下文 + * @return BackupUtils实例 + */ public static synchronized BackupUtils getInstance(Context context) { - if (sInstance == null) { - sInstance = new BackupUtils(context); + if (sInstance == null) { // 检查实例是否已创建 + sInstance = new BackupUtils(context); // 创建新实例 } - return sInstance; + return sInstance; // 返回实例 } /** - * Following states are signs to represents backup or restore - * status + * 以下状态常量用于表示备份或恢复操作的状态 */ - // Currently, the sdcard is not mounted + // 当前SD卡未挂载 public static final int STATE_SD_CARD_UNMOUONTED = 0; - // The backup file not exist + // 备份文件不存在 public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; - // The data is not well formated, may be changed by other programs + // 数据格式不正确,可能被其他程序修改 public static final int STATE_DATA_DESTROIED = 2; - // Some run-time exception which causes restore or backup fails + // 运行时异常导致备份或恢复失败 public static final int STATE_SYSTEM_ERROR = 3; - // Backup or restore success + // 备份或恢复成功 public static final int STATE_SUCCESS = 4; - private TextExport mTextExport; + private TextExport mTextExport; // 文本导出器实例 + /** + * 私有构造函数,初始化文本导出器 + * @param context 应用上下文 + */ private BackupUtils(Context context) { - mTextExport = new TextExport(context); + mTextExport = new TextExport(context); // 初始化文本导出器 } + /** + * 检查外部存储是否可用 + * @return 可用返回true,否则返回false + */ private static boolean externalStorageAvailable() { - return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); + return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); // 检查SD卡挂载状态 } + /** + * 导出笔记到文本文件 + * @return 导出状态码 + */ public int exportToText() { - return mTextExport.exportToText(); + return mTextExport.exportToText(); // 调用文本导出器的导出方法 } + /** + * 获取导出的文本文件名 + * @return 文件名 + */ public String getExportedTextFileName() { - return mTextExport.mFileName; + return mTextExport.mFileName; // 返回导出的文件名 } + /** + * 获取导出的文本文件目录 + * @return 文件目录路径 + */ public String getExportedTextFileDir() { - return mTextExport.mFileDirectory; + return mTextExport.mFileDirectory; // 返回导出的文件目录 } + /** + * 内部类:文本导出器,负责将笔记导出为文本格式 + */ private static class TextExport { + // 笔记查询投影,指定要查询的列 private static final String[] NOTE_PROJECTION = { - NoteColumns.ID, - NoteColumns.MODIFIED_DATE, - NoteColumns.SNIPPET, - NoteColumns.TYPE + NoteColumns.ID, // 笔记ID + NoteColumns.MODIFIED_DATE, // 修改日期 + NoteColumns.SNIPPET, // 摘要 + NoteColumns.TYPE // 类型 }; - private static final int NOTE_COLUMN_ID = 0; - - private static final int NOTE_COLUMN_MODIFIED_DATE = 1; - - private static final int NOTE_COLUMN_SNIPPET = 2; + // 笔记列索引常量 + private static final int NOTE_COLUMN_ID = 0; // ID列索引 + private static final int NOTE_COLUMN_MODIFIED_DATE = 1; // 修改日期列索引 + private static final int NOTE_COLUMN_SNIPPET = 2; // 摘要列索引 + // 数据查询投影,指定要查询的列 private static final String[] DATA_PROJECTION = { - DataColumns.CONTENT, - DataColumns.MIME_TYPE, - DataColumns.DATA1, - DataColumns.DATA2, - DataColumns.DATA3, - DataColumns.DATA4, + DataColumns.CONTENT, // 内容 + DataColumns.MIME_TYPE, // MIME类型 + DataColumns.DATA1, // 数据1(通话日期) + DataColumns.DATA2, // 数据2 + DataColumns.DATA3, // 数据3 + DataColumns.DATA4, // 数据4(电话号码) }; - private static final int DATA_COLUMN_CONTENT = 0; - - private static final int DATA_COLUMN_MIME_TYPE = 1; - - private static final int DATA_COLUMN_CALL_DATE = 2; - - private static final int DATA_COLUMN_PHONE_NUMBER = 4; + // 数据列索引常量 + private static final int DATA_COLUMN_CONTENT = 0; // 内容列索引 + private static final int DATA_COLUMN_MIME_TYPE = 1; // MIME类型列索引 + private static final int DATA_COLUMN_CALL_DATE = 2; // 通话日期列索引 + private static final int DATA_COLUMN_PHONE_NUMBER = 4; // 电话号码列索引 + // 文本格式数组,从资源文件获取 private final String [] TEXT_FORMAT; - private static final int FORMAT_FOLDER_NAME = 0; - private static final int FORMAT_NOTE_DATE = 1; - private static final int FORMAT_NOTE_CONTENT = 2; + // 格式索引常量 + private static final int FORMAT_FOLDER_NAME = 0; // 文件夹名称格式索引 + private static final int FORMAT_NOTE_DATE = 1; // 笔记日期格式索引 + private static final int FORMAT_NOTE_CONTENT = 2; // 笔记内容格式索引 - private Context mContext; - private String mFileName; - private String mFileDirectory; + private Context mContext; // 应用上下文 + private String mFileName; // 导出的文件名 + private String mFileDirectory; // 导出的文件目录 + /** + * 构造函数,初始化文本导出器 + * @param context 应用上下文 + */ public TextExport(Context context) { - TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); - mContext = context; - mFileName = ""; - mFileDirectory = ""; + TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); // 获取文本格式数组 + mContext = context; // 保存上下文 + mFileName = ""; // 初始化文件名 + mFileDirectory = ""; // 初始化文件目录 } + /** + * 获取指定索引的文本格式 + * @param id 格式索引 + * @return 格式字符串 + */ private String getFormat(int id) { - return TEXT_FORMAT[id]; + return TEXT_FORMAT[id]; // 返回指定索引的格式字符串 } /** - * Export the folder identified by folder id to text + * 将指定文件夹下的所有笔记导出为文本 + * @param folderId 文件夹ID + * @param ps 打印流,用于输出文本 */ private void exportFolderToText(String folderId, PrintStream ps) { - // Query notes belong to this folder + // 查询属于该文件夹的所有笔记 Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { - folderId + folderId }, null); - if (notesCursor != null) { - if (notesCursor.moveToFirst()) { + if (notesCursor != null) { // 检查游标是否有效 + if (notesCursor.moveToFirst()) { // 移动到第一条记录 do { - // Print note's last modified date + // 打印笔记的最后修改日期 ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( mContext.getString(R.string.format_datetime_mdhm), notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); - // Query data belong to this note + // 查询属于该笔记的数据 String noteId = notesCursor.getString(NOTE_COLUMN_ID); - exportNoteToText(noteId, ps); - } while (notesCursor.moveToNext()); + exportNoteToText(noteId, ps); // 导出笔记内容 + } while (notesCursor.moveToNext()); // 移动到下一条记录 } - notesCursor.close(); + notesCursor.close(); // 关闭游标 } } /** - * Export note identified by id to a print stream + * 将指定ID的笔记导出为文本 + * @param noteId 笔记ID + * @param ps 打印流,用于输出文本 */ private void exportNoteToText(String noteId, PrintStream ps) { + // 查询属于该笔记的所有数据 Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { - noteId + noteId }, null); - if (dataCursor != null) { - if (dataCursor.moveToFirst()) { + if (dataCursor != null) { // 检查游标是否有效 + if (dataCursor.moveToFirst()) { // 移动到第一条记录 do { - String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); - if (DataConstants.CALL_NOTE.equals(mimeType)) { - // Print phone number + String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); // 获取MIME类型 + if (DataConstants.CALL_NOTE.equals(mimeType)) { // 处理通话记录类型 + // 打印电话号码 String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER); long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE); String location = dataCursor.getString(DATA_COLUMN_CONTENT); - if (!TextUtils.isEmpty(phoneNumber)) { + if (!TextUtils.isEmpty(phoneNumber)) { // 检查电话号码是否为空 ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), - phoneNumber)); + phoneNumber)); // 打印电话号码 } - // Print call date + // 打印通话日期 ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat .format(mContext.getString(R.string.format_datetime_mdhm), callDate))); - // Print call attachment location - if (!TextUtils.isEmpty(location)) { + // 打印通话附件位置 + if (!TextUtils.isEmpty(location)) { // 检查位置信息是否为空 ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), - location)); + location)); // 打印位置信息 } - } else if (DataConstants.NOTE.equals(mimeType)) { - String content = dataCursor.getString(DATA_COLUMN_CONTENT); - if (!TextUtils.isEmpty(content)) { + } else if (DataConstants.NOTE.equals(mimeType)) { // 处理普通笔记类型 + String content = dataCursor.getString(DATA_COLUMN_CONTENT); // 获取笔记内容 + if (!TextUtils.isEmpty(content)) { // 检查内容是否为空 ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), - content)); + content)); // 打印笔记内容 } } - } while (dataCursor.moveToNext()); + } while (dataCursor.moveToNext()); // 移动到下一条记录 } - dataCursor.close(); + dataCursor.close(); // 关闭游标 } - // print a line separator between note + // 在笔记之间打印行分隔符 try { ps.write(new byte[] { Character.LINE_SEPARATOR, Character.LETTER_NUMBER }); } catch (IOException e) { - Log.e(TAG, e.toString()); + Log.e(TAG, e.toString()); // 记录异常信息 } } /** - * Note will be exported as text which is user readable + * 将笔记导出为用户可读的文本格式 + * @return 导出状态码 */ public int exportToText() { - if (!externalStorageAvailable()) { - Log.d(TAG, "Media was not mounted"); - return STATE_SD_CARD_UNMOUONTED; + if (!externalStorageAvailable()) { // 检查外部存储是否可用 + Log.d(TAG, "Media was not mounted"); // 记录日志 + return STATE_SD_CARD_UNMOUONTED; // 返回SD卡未挂载状态 } - PrintStream ps = getExportToTextPrintStream(); - if (ps == null) { - Log.e(TAG, "get print stream error"); - return STATE_SYSTEM_ERROR; + PrintStream ps = getExportToTextPrintStream(); // 获取打印流 + if (ps == null) { // 检查打印流是否获取成功 + Log.e(TAG, "get print stream error"); // 记录错误日志 + return STATE_SYSTEM_ERROR; // 返回系统错误状态 } - // First export folder and its notes + // 首先导出文件夹及其包含的笔记 Cursor folderCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, @@ -237,108 +280,112 @@ public class BackupUtils { + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR " + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null); - if (folderCursor != null) { - if (folderCursor.moveToFirst()) { + if (folderCursor != null) { // 检查游标是否有效 + if (folderCursor.moveToFirst()) { // 移动到第一条记录 do { - // Print folder's name + // 打印文件夹名称 String folderName = ""; if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) { - folderName = mContext.getString(R.string.call_record_folder_name); + folderName = mContext.getString(R.string.call_record_folder_name); // 获取通话记录文件夹名称 } else { - folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET); + folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET); // 获取文件夹摘要作为名称 } - if (!TextUtils.isEmpty(folderName)) { - ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName)); + if (!TextUtils.isEmpty(folderName)) { // 检查文件夹名称是否为空 + ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName)); // 打印文件夹名称 } - String folderId = folderCursor.getString(NOTE_COLUMN_ID); - exportFolderToText(folderId, ps); - } while (folderCursor.moveToNext()); + String folderId = folderCursor.getString(NOTE_COLUMN_ID); // 获取文件夹ID + exportFolderToText(folderId, ps); // 导出文件夹中的笔记 + } while (folderCursor.moveToNext()); // 移动到下一条记录 } - folderCursor.close(); + folderCursor.close(); // 关闭游标 } - // Export notes in root's folder + // 导出根文件夹中的笔记 Cursor noteCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID + "=0", null, null); - if (noteCursor != null) { - if (noteCursor.moveToFirst()) { + if (noteCursor != null) { // 检查游标是否有效 + if (noteCursor.moveToFirst()) { // 移动到第一条记录 do { + // 打印笔记的最后修改日期 ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( mContext.getString(R.string.format_datetime_mdhm), noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); - // Query data belong to this note + // 查询属于该笔记的数据 String noteId = noteCursor.getString(NOTE_COLUMN_ID); - exportNoteToText(noteId, ps); - } while (noteCursor.moveToNext()); + exportNoteToText(noteId, ps); // 导出笔记内容 + } while (noteCursor.moveToNext()); // 移动到下一条记录 } - noteCursor.close(); + noteCursor.close(); // 关闭游标 } - ps.close(); + ps.close(); // 关闭打印流 - return STATE_SUCCESS; + return STATE_SUCCESS; // 返回成功状态 } /** - * Get a print stream pointed to the file {@generateExportedTextFile} + * 获取指向导出文本文件的打印流 + * @return 打印流对象,失败时返回null */ private PrintStream getExportToTextPrintStream() { File file = generateFileMountedOnSDcard(mContext, R.string.file_path, - R.string.file_name_txt_format); - if (file == null) { - Log.e(TAG, "create file to exported failed"); - return null; + R.string.file_name_txt_format); // 生成SD卡上的文件 + if (file == null) { // 检查文件是否生成成功 + Log.e(TAG, "create file to exported failed"); // 记录错误日志 + return null; // 返回null表示失败 } - mFileName = file.getName(); - mFileDirectory = mContext.getString(R.string.file_path); - PrintStream ps = null; + mFileName = file.getName(); // 保存文件名 + mFileDirectory = mContext.getString(R.string.file_path); // 保存文件目录 + PrintStream ps = null; // 初始化打印流 try { - FileOutputStream fos = new FileOutputStream(file); - ps = new PrintStream(fos); - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; - } catch (NullPointerException e) { - e.printStackTrace(); - return null; + FileOutputStream fos = new FileOutputStream(file); // 创建文件输出流 + ps = new PrintStream(fos); // 创建打印流 + } catch (FileNotFoundException e) { // 处理文件未找到异常 + e.printStackTrace(); // 打印异常堆栈 + return null; // 返回null表示失败 + } catch (NullPointerException e) { // 处理空指针异常 + e.printStackTrace(); // 打印异常堆栈 + return null; // 返回null表示失败 } - return ps; + return ps; // 返回打印流 } } /** - * Generate the text file to store imported data + * 生成挂载在SD卡上的文件 + * @param context 应用上下文 + * @param filePathResId 文件路径资源ID + * @param fileNameFormatResId 文件名格式资源ID + * @return 生成的文件对象,失败时返回null */ private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { - StringBuilder sb = new StringBuilder(); - sb.append(Environment.getExternalStorageDirectory()); - sb.append(context.getString(filePathResId)); - File filedir = new File(sb.toString()); + StringBuilder sb = new StringBuilder(); // 创建字符串构建器 + sb.append(Environment.getExternalStorageDirectory()); // 添加外部存储目录 + sb.append(context.getString(filePathResId)); // 添加文件路径 + File filedir = new File(sb.toString()); // 创建目录对象 sb.append(context.getString( fileNameFormatResId, DateFormat.format(context.getString(R.string.format_date_ymd), - System.currentTimeMillis()))); - File file = new File(sb.toString()); + System.currentTimeMillis()))); // 添加带日期的文件名 + File file = new File(sb.toString()); // 创建文件对象 try { - if (!filedir.exists()) { - filedir.mkdir(); + if (!filedir.exists()) { // 检查目录是否存在 + filedir.mkdir(); // 创建目录 } - if (!file.exists()) { - file.createNewFile(); + if (!file.exists()) { // 检查文件是否存在 + file.createNewFile(); // 创建文件 } - return file; - } catch (SecurityException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + return file; // 返回文件对象 + } catch (SecurityException e) { // 处理安全异常 + e.printStackTrace(); // 打印异常堆栈 + } catch (IOException e) { // 处理IO异常 + e.printStackTrace(); // 打印异常堆栈 } - return null; + return null; // 返回null表示失败 } -} - - +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/tool/DataUtils.java b/src/Notes-master/src/net/micode/notes/tool/DataUtils.java index 2a14982..652740b 100644 --- a/src/Notes-master/src/net/micode/notes/tool/DataUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/DataUtils.java @@ -2,294 +2,379 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ -package net.micode.notes.tool; +package net.micode.notes.tool; // 指定代码所属的包名 -import android.content.ContentProviderOperation; -import android.content.ContentProviderResult; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.OperationApplicationException; -import android.database.Cursor; -import android.os.RemoteException; -import android.util.Log; +import android.content.ContentProviderOperation; // 导入内容提供者操作类 +import android.content.ContentProviderResult; // 导入内容提供者结果类 +import android.content.ContentResolver; // 导入内容解析器类 +import android.content.ContentUris; // 导入内容URI工具类 +import android.content.ContentValues; // 导入内容值类 +import android.content.OperationApplicationException; // 导入操作应用异常类 +import android.database.Cursor; // 导入数据库游标类 +import android.os.RemoteException; // 导入远程异常类 +import android.util.Log; // 导入日志记录类 -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.CallNote; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; - -import java.util.ArrayList; -import java.util.HashSet; +import net.micode.notes.data.Notes; // 导入笔记数据类 +import net.micode.notes.data.Notes.CallNote; // 导入通话记录数据类 +import net.micode.notes.data.Notes.NoteColumns; // 导入笔记列定义类 +import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; // 导入应用小部件属性类 +import java.util.ArrayList; // 导入ArrayList类 +import java.util.HashSet; // 导入HashSet类 +/** + * 数据工具类,提供与笔记数据操作相关的实用方法 + * 包括批量删除、移动笔记、查询文件夹和笔记信息等功能 + */ public class DataUtils { - public static final String TAG = "DataUtils"; + public static final String TAG = "DataUtils"; // 日志标签 + + /** + * 批量删除笔记 + * @param resolver 内容解析器 + * @param ids 要删除的笔记ID集合 + * @return 删除成功返回true,失败返回false + */ public static boolean batchDeleteNotes(ContentResolver resolver, HashSet ids) { - if (ids == null) { + if (ids == null) { // 检查ID集合是否为空 Log.d(TAG, "the ids is null"); - return true; + return true; // 空集合视为操作成功 } - if (ids.size() == 0) { + if (ids.size() == 0) { // 检查ID集合是否为空 Log.d(TAG, "no id is in the hashset"); - return true; + return true; // 空集合视为操作成功 } - ArrayList operationList = new ArrayList(); - for (long id : ids) { - if(id == Notes.ID_ROOT_FOLDER) { + ArrayList operationList = new ArrayList<>(); // 创建操作列表 + for (long id : ids) { // 遍历ID集合 + if(id == Notes.ID_ROOT_FOLDER) { // 检查是否为根文件夹 Log.e(TAG, "Don't delete system folder root"); - continue; + continue; // 跳过根文件夹,不删除 } ContentProviderOperation.Builder builder = ContentProviderOperation - .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); - operationList.add(builder.build()); + .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); // 创建删除操作 + operationList.add(builder.build()); // 将操作添加到列表 } try { - ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); - if (results == null || results.length == 0 || results[0] == null) { + ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); // 执行批量操作 + if (results == null || results.length == 0 || results[0] == null) { // 检查操作结果 Log.d(TAG, "delete notes failed, ids:" + ids.toString()); - return false; + return false; // 操作失败 } - return true; - } catch (RemoteException e) { + return true; // 操作成功 + } catch (RemoteException e) { // 处理远程异常 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - } catch (OperationApplicationException e) { + } catch (OperationApplicationException e) { // 处理操作应用异常 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } - return false; + return false; // 发生异常,操作失败 } + /** + * 将笔记移动到指定文件夹 + * @param resolver 内容解析器 + * @param id 笔记ID + * @param srcFolderId 源文件夹ID + * @param desFolderId 目标文件夹ID + */ public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) { - ContentValues values = new ContentValues(); - values.put(NoteColumns.PARENT_ID, desFolderId); - values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); - values.put(NoteColumns.LOCAL_MODIFIED, 1); - resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); + ContentValues values = new ContentValues(); // 创建内容值对象 + values.put(NoteColumns.PARENT_ID, desFolderId); // 设置目标文件夹ID + values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); // 设置源文件夹ID + values.put(NoteColumns.LOCAL_MODIFIED, 1); // 标记为本地已修改 + resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); // 更新笔记 } + /** + * 批量将笔记移动到指定文件夹 + * @param resolver 内容解析器 + * @param ids 要移动的笔记ID集合 + * @param folderId 目标文件夹ID + * @return 移动成功返回true,失败返回false + */ public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids, - long folderId) { - if (ids == null) { + long folderId) { + if (ids == null) { // 检查ID集合是否为空 Log.d(TAG, "the ids is null"); - return true; + return true; // 空集合视为操作成功 } - ArrayList operationList = new ArrayList(); - for (long id : ids) { + ArrayList operationList = new ArrayList<>(); // 创建操作列表 + for (long id : ids) { // 遍历ID集合 ContentProviderOperation.Builder builder = ContentProviderOperation - .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); - builder.withValue(NoteColumns.PARENT_ID, folderId); - builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); - operationList.add(builder.build()); + .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); // 创建更新操作 + builder.withValue(NoteColumns.PARENT_ID, folderId); // 设置目标文件夹ID + builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); // 标记为本地已修改 + operationList.add(builder.build()); // 将操作添加到列表 } try { - ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); - if (results == null || results.length == 0 || results[0] == null) { + ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); // 执行批量操作 + if (results == null || results.length == 0 || results[0] == null) { // 检查操作结果 Log.d(TAG, "delete notes failed, ids:" + ids.toString()); - return false; + return false; // 操作失败 } - return true; - } catch (RemoteException e) { + return true; // 操作成功 + } catch (RemoteException e) { // 处理远程异常 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - } catch (OperationApplicationException e) { + } catch (OperationApplicationException e) { // 处理操作应用异常 Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); } - return false; + return false; // 发生异常,操作失败 } /** - * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}} + * 获取用户文件夹数量(不包括系统文件夹) + * @param resolver 内容解析器 + * @return 用户文件夹数量 */ public static int getUserFolderCount(ContentResolver resolver) { - Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI, - new String[] { "COUNT(*)" }, - NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", - new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, - null); + Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, // 查询笔记表 + new String[] { "COUNT(*)" }, // 查询数量 + NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", // 查询条件:类型为文件夹且不在回收站 + new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, // 查询参数 + null); // 排序方式 - int count = 0; - if(cursor != null) { - if(cursor.moveToFirst()) { + int count = 0; // 初始化数量为0 + if(cursor != null) { // 检查游标是否有效 + if(cursor.moveToFirst()) { // 移动到第一条记录 try { - count = cursor.getInt(0); - } catch (IndexOutOfBoundsException e) { + count = cursor.getInt(0); // 获取数量值 + } catch (IndexOutOfBoundsException e) { // 处理索引越界异常 Log.e(TAG, "get folder count failed:" + e.toString()); } finally { - cursor.close(); + cursor.close(); // 关闭游标 } } } - return count; + return count; // 返回文件夹数量 } + /** + * 检查笔记是否在数据库中可见(存在且不在回收站) + * @param resolver 内容解析器 + * @param noteId 笔记ID + * @param type 笔记类型 + * @return 可见返回true,否则返回false + */ public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { - Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), - null, - NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, - new String [] {String.valueOf(type)}, - null); + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), // 查询指定笔记 + null, // 查询所有列 + NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, // 查询条件:类型匹配且不在回收站 + new String [] {String.valueOf(type)}, // 查询参数 + null); // 排序方式 - boolean exist = false; - if (cursor != null) { - if (cursor.getCount() > 0) { - exist = true; + boolean exist = false; // 初始化存在标志为false + if (cursor != null) { // 检查游标是否有效 + if (cursor.getCount() > 0) { // 检查记录数量 + exist = true; // 存在记录,设置标志为true } - cursor.close(); + cursor.close(); // 关闭游标 } - return exist; + return exist; // 返回存在标志 } + /** + * 检查笔记是否存在于数据库中 + * @param resolver 内容解析器 + * @param noteId 笔记ID + * @return 存在返回true,否则返回false + */ public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { - Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), - null, null, null, null); + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), // 查询指定笔记 + null, // 查询所有列 + null, // 无查询条件 + null, // 无查询参数 + null); // 排序方式 - boolean exist = false; - if (cursor != null) { - if (cursor.getCount() > 0) { - exist = true; + boolean exist = false; // 初始化存在标志为false + if (cursor != null) { // 检查游标是否有效 + if (cursor.getCount() > 0) { // 检查记录数量 + exist = true; // 存在记录,设置标志为true } - cursor.close(); + cursor.close(); // 关闭游标 } - return exist; + return exist; // 返回存在标志 } + /** + * 检查数据项是否存在于数据库中 + * @param resolver 内容解析器 + * @param dataId 数据ID + * @return 存在返回true,否则返回false + */ public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { - Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), - null, null, null, null); + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), // 查询指定数据项 + null, // 查询所有列 + null, // 无查询条件 + null, // 无查询参数 + null); // 排序方式 - boolean exist = false; - if (cursor != null) { - if (cursor.getCount() > 0) { - exist = true; + boolean exist = false; // 初始化存在标志为false + if (cursor != null) { // 检查游标是否有效 + if (cursor.getCount() > 0) { // 检查记录数量 + exist = true; // 存在记录,设置标志为true } - cursor.close(); + cursor.close(); // 关闭游标 } - return exist; + return exist; // 返回存在标志 } + /** + * 检查可见文件夹名称是否已存在 + * @param resolver 内容解析器 + * @param name 文件夹名称 + * @return 存在返回true,否则返回false + */ public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { - Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, - NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + - " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + - " AND " + NoteColumns.SNIPPET + "=?", - new String[] { name }, null); - boolean exist = false; - if(cursor != null) { - if(cursor.getCount() > 0) { - exist = true; + Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, // 查询笔记表 + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + // 查询条件:类型为文件夹 + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + // 且不在回收站 + " AND " + NoteColumns.SNIPPET + "=?", // 且名称匹配 + new String[] { name }, null); // 查询参数 + boolean exist = false; // 初始化存在标志为false + if(cursor != null) { // 检查游标是否有效 + if(cursor.getCount() > 0) { // 检查记录数量 + exist = true; // 存在记录,设置标志为true } - cursor.close(); + cursor.close(); // 关闭游标 } - return exist; + return exist; // 返回存在标志 } + /** + * 获取指定文件夹下的所有笔记小部件属性 + * @param resolver 内容解析器 + * @param folderId 文件夹ID + * @return 小部件属性集合 + */ public static HashSet getFolderNoteWidget(ContentResolver resolver, long folderId) { - Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, - new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, - NoteColumns.PARENT_ID + "=?", - new String[] { String.valueOf(folderId) }, - null); + Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, // 查询笔记表 + new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, // 查询小部件ID和类型 + NoteColumns.PARENT_ID + "=?", // 查询条件:父文件夹ID匹配 + new String[] { String.valueOf(folderId) }, // 查询参数 + null); // 排序方式 - HashSet set = null; - if (c != null) { - if (c.moveToFirst()) { - set = new HashSet(); + HashSet set = null; // 初始化集合为null + if (c != null) { // 检查游标是否有效 + if (c.moveToFirst()) { // 移动到第一条记录 + set = new HashSet<>(); // 创建集合 do { try { - AppWidgetAttribute widget = new AppWidgetAttribute(); - widget.widgetId = c.getInt(0); - widget.widgetType = c.getInt(1); - set.add(widget); - } catch (IndexOutOfBoundsException e) { + AppWidgetAttribute widget = new AppWidgetAttribute(); // 创建小部件属性对象 + widget.widgetId = c.getInt(0); // 设置小部件ID + widget.widgetType = c.getInt(1); // 设置小部件类型 + set.add(widget); // 将小部件属性添加到集合 + } catch (IndexOutOfBoundsException e) { // 处理索引越界异常 Log.e(TAG, e.toString()); } - } while (c.moveToNext()); + } while (c.moveToNext()); // 移动到下一条记录 } - c.close(); + c.close(); // 关闭游标 } - return set; + return set; // 返回集合 } + /** + * 根据笔记ID获取通话号码 + * @param resolver 内容解析器 + * @param noteId 笔记ID + * @return 通话号码,不存在则返回空字符串 + */ public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { - Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, - new String [] { CallNote.PHONE_NUMBER }, - CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", - new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }, - null); + Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, // 查询数据表 + new String [] { CallNote.PHONE_NUMBER }, // 查询电话号码列 + CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", // 查询条件:笔记ID匹配且类型为通话记录 + new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }, // 查询参数 + null); // 排序方式 - if (cursor != null && cursor.moveToFirst()) { + if (cursor != null && cursor.moveToFirst()) { // 检查游标是否有效并移动到第一条记录 try { - return cursor.getString(0); - } catch (IndexOutOfBoundsException e) { + return cursor.getString(0); // 返回电话号码 + } catch (IndexOutOfBoundsException e) { // 处理索引越界异常 Log.e(TAG, "Get call number fails " + e.toString()); } finally { - cursor.close(); + cursor.close(); // 关闭游标 } } - return ""; + return ""; // 未找到返回空字符串 } + /** + * 根据电话号码和通话日期获取笔记ID + * @param resolver 内容解析器 + * @param phoneNumber 电话号码 + * @param callDate 通话日期 + * @return 笔记ID,不存在则返回0 + */ public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { - Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, - new String [] { CallNote.NOTE_ID }, - CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" - + CallNote.PHONE_NUMBER + ",?)", - new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, - null); + Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, // 查询数据表 + new String [] { CallNote.NOTE_ID }, // 查询笔记ID列 + CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" // 查询条件:日期匹配、类型为通话记录且电话号码相等 + + CallNote.PHONE_NUMBER + ",?)", + new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, // 查询参数 + null); // 排序方式 - if (cursor != null) { - if (cursor.moveToFirst()) { + if (cursor != null) { // 检查游标是否有效 + if (cursor.moveToFirst()) { // 移动到第一条记录 try { - return cursor.getLong(0); - } catch (IndexOutOfBoundsException e) { + return cursor.getLong(0); // 返回笔记ID + } catch (IndexOutOfBoundsException e) { // 处理索引越界异常 Log.e(TAG, "Get call note id fails " + e.toString()); } } - cursor.close(); + cursor.close(); // 关闭游标 } - return 0; + return 0; // 未找到返回0 } + /** + * 根据笔记ID获取摘要 + * @param resolver 内容解析器 + * @param noteId 笔记ID + * @return 摘要内容 + * @throws IllegalArgumentException 笔记不存在时抛出异常 + */ public static String getSnippetById(ContentResolver resolver, long noteId) { - Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, - new String [] { NoteColumns.SNIPPET }, - NoteColumns.ID + "=?", - new String [] { String.valueOf(noteId)}, - null); + Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, // 查询笔记表 + new String [] { NoteColumns.SNIPPET }, // 查询摘要列 + NoteColumns.ID + "=?", // 查询条件:笔记ID匹配 + new String [] { String.valueOf(noteId)}, // 查询参数 + null); // 排序方式 - if (cursor != null) { - String snippet = ""; - if (cursor.moveToFirst()) { - snippet = cursor.getString(0); + if (cursor != null) { // 检查游标是否有效 + String snippet = ""; // 初始化摘要为空字符串 + if (cursor.moveToFirst()) { // 移动到第一条记录 + snippet = cursor.getString(0); // 获取摘要内容 } - cursor.close(); - return snippet; + cursor.close(); // 关闭游标 + return snippet; // 返回摘要 } - throw new IllegalArgumentException("Note is not found with id: " + noteId); + throw new IllegalArgumentException("Note is not found with id: " + noteId); // 未找到笔记,抛出异常 } + /** + * 格式化摘要内容(截取第一行) + * @param snippet 原始摘要 + * @return 格式化后的摘要 + */ public static String getFormattedSnippet(String snippet) { - if (snippet != null) { - snippet = snippet.trim(); - int index = snippet.indexOf('\n'); - if (index != -1) { - snippet = snippet.substring(0, index); + if (snippet != null) { // 检查摘要是否为空 + snippet = snippet.trim(); // 去除前后空格 + int index = snippet.indexOf('\n'); // 查找换行符位置 + if (index != -1) { // 如果存在换行符 + snippet = snippet.substring(0, index); // 截取第一行 } } - return snippet; + return snippet; // 返回格式化后的摘要 } -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java b/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java index 666b729..38f639b 100644 --- a/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java +++ b/src/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java @@ -2,112 +2,118 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ -package net.micode.notes.tool; +package net.micode.notes.tool; // 指定代码所属的包名 +/** + * Google Tasks 相关字符串常量工具类 + * 定义与Google Tasks服务交互时使用的JSON字段名、文件夹名称、元数据标识等常量 + */ public class GTaskStringUtils { + // --------------------------- JSON 字段常量 --------------------------- // + // 操作ID字段名 public final static String GTASK_JSON_ACTION_ID = "action_id"; - + // 操作列表字段名 public final static String GTASK_JSON_ACTION_LIST = "action_list"; - + // 操作类型字段名 public final static String GTASK_JSON_ACTION_TYPE = "action_type"; - + // 创建操作类型值 public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create"; - + // 获取全部数据操作类型值 public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all"; - + // 移动操作类型值 public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move"; - + // 更新操作类型值 public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update"; - + // 创建者ID字段名 public final static String GTASK_JSON_CREATOR_ID = "creator_id"; - + // 子实体字段名 public final static String GTASK_JSON_CHILD_ENTITY = "child_entity"; - + // 客户端版本字段名 public final static String GTASK_JSON_CLIENT_VERSION = "client_version"; - + // 完成状态字段名 public final static String GTASK_JSON_COMPLETED = "completed"; - + // 当前列表ID字段名 public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id"; - + // 默认列表ID字段名 public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id"; - + // 已删除状态字段名 public final static String GTASK_JSON_DELETED = "deleted"; - + // 目标列表字段名(移动操作) public final static String GTASK_JSON_DEST_LIST = "dest_list"; - + // 目标父级字段名(移动操作) public final static String GTASK_JSON_DEST_PARENT = "dest_parent"; - + // 目标父级类型字段名 public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type"; - + // 实体变更字段名 public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta"; - + // 实体类型字段名 public final static String GTASK_JSON_ENTITY_TYPE = "entity_type"; - + // 是否获取已删除数据字段名 public final static String GTASK_JSON_GET_DELETED = "get_deleted"; - + // ID字段名 public final static String GTASK_JSON_ID = "id"; - + // 索引字段名 public final static String GTASK_JSON_INDEX = "index"; - + // 最后修改时间字段名 public final static String GTASK_JSON_LAST_MODIFIED = "last_modified"; - + // 最新同步点字段名 public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point"; - + // 列表ID字段名 public final static String GTASK_JSON_LIST_ID = "list_id"; - + // 列表集合字段名 public final static String GTASK_JSON_LISTS = "lists"; - + // 名称字段名 public final static String GTASK_JSON_NAME = "name"; - + // 新ID字段名(创建操作返回) public final static String GTASK_JSON_NEW_ID = "new_id"; - + // 备注字段名 public final static String GTASK_JSON_NOTES = "notes"; - + // 父级ID字段名 public final static String GTASK_JSON_PARENT_ID = "parent_id"; - + // 前一个兄弟ID字段名(排序用) public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id"; - + // 结果集合字段名 public final static String GTASK_JSON_RESULTS = "results"; - + // 源列表字段名(移动操作) public final static String GTASK_JSON_SOURCE_LIST = "source_list"; - + // 任务集合字段名 public final static String GTASK_JSON_TASKS = "tasks"; - + // 类型字段名 public final static String GTASK_JSON_TYPE = "type"; - + // 分组类型值 public final static String GTASK_JSON_TYPE_GROUP = "GROUP"; - + // 任务类型值 public final static String GTASK_JSON_TYPE_TASK = "TASK"; - + // 用户字段名 public final static String GTASK_JSON_USER = "user"; + // --------------------------- 文件夹相关常量 --------------------------- // + // MIUI笔记文件夹前缀(用于标识本地创建的文件夹) public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]"; - + // 默认文件夹名称 public final static String FOLDER_DEFAULT = "Default"; - + // 通话记录文件夹名称 public final static String FOLDER_CALL_NOTE = "Call_Note"; - + // 元数据文件夹名称(存储同步元数据) public final static String FOLDER_META = "METADATA"; + // --------------------------- 元数据相关常量 --------------------------- // + // 元数据头部:Google Tasks ID标识 public final static String META_HEAD_GTASK_ID = "meta_gid"; - + // 元数据头部:笔记内容标识 public final static String META_HEAD_NOTE = "meta_note"; - + // 元数据头部:数据项标识 public final static String META_HEAD_DATA = "meta_data"; - + // 元数据笔记名称(系统自动生成,禁止用户修改/删除) public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE"; - -} +} \ No newline at end of file diff --git a/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java b/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java index 1ad3ad6..ebb3dbd 100644 --- a/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java +++ b/src/Notes-master/src/net/micode/notes/tool/ResourceParser.java @@ -2,180 +2,270 @@ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 您可以在遵守 License 的前提下使用本文件。 + * 您可以从以下地址获取 License 副本: * * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * 除非适用法律要求或书面同意,本软件根据 License 分发时“按现状”提供, + * 不附带任何明示或暗示的保证或条件。请参阅 License 了解具体的权限和限制。 */ -package net.micode.notes.tool; +package net.micode.notes.tool; // 指定代码所属的包名 -import android.content.Context; -import android.preference.PreferenceManager; +import android.content.Context; // 导入Context类,提供应用环境信息 +import android.preference.PreferenceManager; // 导入偏好设置管理类 -import net.micode.notes.R; -import net.micode.notes.ui.NotesPreferenceActivity; +import net.micode.notes.R; // 导入R资源类,访问应用资源 +import net.micode.notes.ui.NotesPreferenceActivity; // 导入笔记偏好设置活动类 +/** + * 资源解析工具类,用于管理和获取笔记应用中的各种资源 + * 包括背景颜色、文本大小、布局样式等资源的ID映射和解析 + */ public class ResourceParser { - public static final int YELLOW = 0; - public static final int BLUE = 1; - public static final int WHITE = 2; - public static final int GREEN = 3; - public static final int RED = 4; + // 笔记背景颜色常量定义 + public static final int YELLOW = 0; // 黄色背景 + public static final int BLUE = 1; // 蓝色背景 + public static final int WHITE = 2; // 白色背景 + public static final int GREEN = 3; // 绿色背景 + public static final int RED = 4; // 红色背景 + // 默认背景颜色(黄色) public static final int BG_DEFAULT_COLOR = YELLOW; - public static final int TEXT_SMALL = 0; - public static final int TEXT_MEDIUM = 1; - public static final int TEXT_LARGE = 2; - public static final int TEXT_SUPER = 3; + // 文本大小常量定义 + public static final int TEXT_SMALL = 0; // 小号文本 + public static final int TEXT_MEDIUM = 1; // 中号文本(默认) + public static final int TEXT_LARGE = 2; // 大号文本 + public static final int TEXT_SUPER = 3; // 超大号文本 + // 默认文本大小(中号) public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM; + /** + * 笔记编辑界面背景资源内部类 + * 管理笔记编辑界面的背景和标题栏背景资源ID + */ public static class NoteBgResources { + // 笔记编辑界面背景资源数组 private final static int [] BG_EDIT_RESOURCES = new int [] { - R.drawable.edit_yellow, - R.drawable.edit_blue, - R.drawable.edit_white, - R.drawable.edit_green, - R.drawable.edit_red + R.drawable.edit_yellow, // 黄色背景 + R.drawable.edit_blue, // 蓝色背景 + R.drawable.edit_white, // 白色背景 + R.drawable.edit_green, // 绿色背景 + R.drawable.edit_red // 红色背景 }; + // 笔记编辑界面标题栏背景资源数组 private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] { - R.drawable.edit_title_yellow, - R.drawable.edit_title_blue, - R.drawable.edit_title_white, - R.drawable.edit_title_green, - R.drawable.edit_title_red + R.drawable.edit_title_yellow, // 黄色标题栏 + R.drawable.edit_title_blue, // 蓝色标题栏 + R.drawable.edit_title_white, // 白色标题栏 + R.drawable.edit_title_green, // 绿色标题栏 + R.drawable.edit_title_red // 红色标题栏 }; + /** + * 根据颜色ID获取笔记编辑界面背景资源ID + * @param id 颜色ID(0-4) + * @return 对应的背景资源ID + */ public static int getNoteBgResource(int id) { - return BG_EDIT_RESOURCES[id]; + return BG_EDIT_RESOURCES[id]; // 返回对应颜色的背景资源ID } + /** + * 根据颜色ID获取笔记编辑界面标题栏背景资源ID + * @param id 颜色ID(0-4) + * @return 对应的标题栏背景资源ID + */ public static int getNoteTitleBgResource(int id) { - return BG_EDIT_TITLE_RESOURCES[id]; + return BG_EDIT_TITLE_RESOURCES[id]; // 返回对应颜色的标题栏背景资源ID } } + /** + * 获取默认笔记背景ID + * 根据用户偏好设置决定是返回随机背景还是默认背景 + * @param context 应用上下文 + * @return 背景ID + */ public static int getDefaultBgId(Context context) { if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { + // 如果用户开启了随机背景选项,则返回随机背景ID return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length); } else { + // 否则返回默认背景ID(黄色) return BG_DEFAULT_COLOR; } } + /** + * 笔记列表项背景资源内部类 + * 管理笔记在列表中不同位置(首项、中间项、末项、单项)的背景资源ID + */ public static class NoteItemBgResources { + // 列表中第一项的背景资源数组 private final static int [] BG_FIRST_RESOURCES = new int [] { - R.drawable.list_yellow_up, - R.drawable.list_blue_up, - R.drawable.list_white_up, - R.drawable.list_green_up, - R.drawable.list_red_up + R.drawable.list_yellow_up, // 黄色首项背景 + R.drawable.list_blue_up, // 蓝色首项背景 + R.drawable.list_white_up, // 白色首项背景 + R.drawable.list_green_up, // 绿色首项背景 + R.drawable.list_red_up // 红色首项背景 }; + // 列表中中间项的背景资源数组 private final static int [] BG_NORMAL_RESOURCES = new int [] { - R.drawable.list_yellow_middle, - R.drawable.list_blue_middle, - R.drawable.list_white_middle, - R.drawable.list_green_middle, - R.drawable.list_red_middle + R.drawable.list_yellow_middle, // 黄色中间项背景 + R.drawable.list_blue_middle, // 蓝色中间项背景 + R.drawable.list_white_middle, // 白色中间项背景 + R.drawable.list_green_middle, // 绿色中间项背景 + R.drawable.list_red_middle // 红色中间项背景 }; + // 列表中最后一项的背景资源数组 private final static int [] BG_LAST_RESOURCES = new int [] { - R.drawable.list_yellow_down, - R.drawable.list_blue_down, - R.drawable.list_white_down, - R.drawable.list_green_down, - R.drawable.list_red_down, + R.drawable.list_yellow_down, // 黄色末项背景 + R.drawable.list_blue_down, // 蓝色末项背景 + R.drawable.list_white_down, // 白色末项背景 + R.drawable.list_green_down, // 绿色末项背景 + R.drawable.list_red_down, // 红色末项背景 }; + // 列表中单独一项(唯一项)的背景资源数组 private final static int [] BG_SINGLE_RESOURCES = new int [] { - R.drawable.list_yellow_single, - R.drawable.list_blue_single, - R.drawable.list_white_single, - R.drawable.list_green_single, - R.drawable.list_red_single + R.drawable.list_yellow_single, // 黄色单项背景 + R.drawable.list_blue_single, // 蓝色单项背景 + R.drawable.list_white_single, // 白色单项背景 + R.drawable.list_green_single, // 绿色单项背景 + R.drawable.list_red_single // 红色单项背景 }; + /** + * 根据颜色ID获取列表首项背景资源ID + * @param id 颜色ID(0-4) + * @return 对应的首项背景资源ID + */ public static int getNoteBgFirstRes(int id) { - return BG_FIRST_RESOURCES[id]; + return BG_FIRST_RESOURCES[id]; // 返回对应颜色的首项背景资源ID } + /** + * 根据颜色ID获取列表末项背景资源ID + * @param id 颜色ID(0-4) + * @return 对应的末项背景资源ID + */ public static int getNoteBgLastRes(int id) { - return BG_LAST_RESOURCES[id]; + return BG_LAST_RESOURCES[id]; // 返回对应颜色的末项背景资源ID } + /** + * 根据颜色ID获取列表单项背景资源ID + * @param id 颜色ID(0-4) + * @return 对应的单项背景资源ID + */ public static int getNoteBgSingleRes(int id) { - return BG_SINGLE_RESOURCES[id]; + return BG_SINGLE_RESOURCES[id]; // 返回对应颜色的单项背景资源ID } + /** + * 根据颜色ID获取列表中间项背景资源ID + * @param id 颜色ID(0-4) + * @return 对应的中间项背景资源ID + */ public static int getNoteBgNormalRes(int id) { - return BG_NORMAL_RESOURCES[id]; + return BG_NORMAL_RESOURCES[id]; // 返回对应颜色的中间项背景资源ID } + /** + * 获取文件夹列表项的背景资源ID + * @return 文件夹背景资源ID + */ public static int getFolderBgRes() { - return R.drawable.list_folder; + return R.drawable.list_folder; // 返回文件夹背景资源ID } } + /** + * 桌面小部件背景资源内部类 + * 管理不同尺寸(2x和4x)桌面小部件的背景资源ID + */ public static class WidgetBgResources { + // 2x尺寸桌面小部件背景资源数组 private final static int [] BG_2X_RESOURCES = new int [] { - R.drawable.widget_2x_yellow, - R.drawable.widget_2x_blue, - R.drawable.widget_2x_white, - R.drawable.widget_2x_green, - R.drawable.widget_2x_red, + R.drawable.widget_2x_yellow, // 黄色2x小部件背景 + R.drawable.widget_2x_blue, // 蓝色2x小部件背景 + R.drawable.widget_2x_white, // 白色2x小部件背景 + R.drawable.widget_2x_green, // 绿色2x小部件背景 + R.drawable.widget_2x_red, // 红色2x小部件背景 }; + /** + * 根据颜色ID获取2x尺寸桌面小部件背景资源ID + * @param id 颜色ID(0-4) + * @return 对应的2x小部件背景资源ID + */ public static int getWidget2xBgResource(int id) { - return BG_2X_RESOURCES[id]; + return BG_2X_RESOURCES[id]; // 返回对应颜色的2x小部件背景资源ID } + // 4x尺寸桌面小部件背景资源数组 private final static int [] BG_4X_RESOURCES = new int [] { - R.drawable.widget_4x_yellow, - R.drawable.widget_4x_blue, - R.drawable.widget_4x_white, - R.drawable.widget_4x_green, - R.drawable.widget_4x_red + R.drawable.widget_4x_yellow, // 黄色4x小部件背景 + R.drawable.widget_4x_blue, // 蓝色4x小部件背景 + R.drawable.widget_4x_white, // 白色4x小部件背景 + R.drawable.widget_4x_green, // 绿色4x小部件背景 + R.drawable.widget_4x_red // 红色4x小部件背景 }; + /** + * 根据颜色ID获取4x尺寸桌面小部件背景资源ID + * @param id 颜色ID(0-4) + * @return 对应的4x小部件背景资源ID + */ public static int getWidget4xBgResource(int id) { - return BG_4X_RESOURCES[id]; + return BG_4X_RESOURCES[id]; // 返回对应颜色的4x小部件背景资源ID } } + /** + * 文本样式资源内部类 + * 管理不同文本大小的样式资源ID + */ public static class TextAppearanceResources { + // 文本样式资源数组 private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] { - R.style.TextAppearanceNormal, - R.style.TextAppearanceMedium, - R.style.TextAppearanceLarge, - R.style.TextAppearanceSuper + R.style.TextAppearanceNormal, // 小号文本样式 + R.style.TextAppearanceMedium, // 中号文本样式 + R.style.TextAppearanceLarge, // 大号文本样式 + R.style.TextAppearanceSuper // 超大号文本样式 }; + /** + * 根据文本大小ID获取对应的文本样式资源ID + * @param id 文本大小ID(0-3) + * @return 对应的文本样式资源ID + */ public static int getTexAppearanceResource(int id) { /** - * HACKME: Fix bug of store the resource id in shared preference. - * The id may larger than the length of resources, in this case, - * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} + * HACKME: 修复在共享偏好中存储资源ID可能导致的问题。 + * 如果ID大于资源数组长度,返回默认文本大小(中号) */ if (id >= TEXTAPPEARANCE_RESOURCES.length) { - return BG_DEFAULT_FONT_SIZE; + return BG_DEFAULT_FONT_SIZE; // ID越界时返回默认文本大小 } - return TEXTAPPEARANCE_RESOURCES[id]; + return TEXTAPPEARANCE_RESOURCES[id]; // 返回对应文本大小的样式资源ID } + /** + * 获取文本样式资源数组的长度 + * @return 资源数组长度 + */ public static int getResourcesSize() { - return TEXTAPPEARANCE_RESOURCES.length; + return TEXTAPPEARANCE_RESOURCES.length; // 返回资源数组长度 } } -} +} \ No newline at end of file From 0ff0d51330090a45cdd3e4fb44e4e50d1e4fa33d Mon Sep 17 00:00:00 2001 From: Wang-YYu-Lu <1756892659@qq.com> Date: Tue, 27 May 2025 09:30:31 +0800 Subject: [PATCH 10/11] =?UTF-8?q?MainActivity.java=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/net/micode/notes/MainActivity.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/Notes-master/src/net/micode/notes/MainActivity.java diff --git a/src/Notes-master/src/net/micode/notes/MainActivity.java b/src/Notes-master/src/net/micode/notes/MainActivity.java new file mode 100644 index 0000000..8e81052 --- /dev/null +++ b/src/Notes-master/src/net/micode/notes/MainActivity.java @@ -0,0 +1,48 @@ +package net.micode.notes; // 指定代码所属的包名 + +import android.os.Bundle; // 导入Bundle类,用于传递和保存状态数据 + +import androidx.activity.EdgeToEdge; // 导入边缘到边缘功能类,支持沉浸式布局 +import androidx.appcompat.app.AppCompatActivity; // 导入AppCompat活动基类,提供兼容性支持 +import androidx.core.graphics.Insets; // 导入Insets类,用于表示窗口插入区域的尺寸 +import androidx.core.view.ViewCompat; // 导入视图兼容工具类,提供跨版本视图功能 +import androidx.core.view.WindowInsetsCompat; // 导入窗口插入兼容类,处理窗口插入事件 + +/** + * 应用主活动类 + * 负责应用的主界面展示和初始化工作 + */ +public class MainActivity extends AppCompatActivity { + + /** + * 活动创建时调用的方法 + * 进行布局初始化和窗口插入事件处理 + * @param savedInstanceState 保存的活动状态,如果活动是重新创建的 + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); // 调用父类的onCreate方法 + + // 启用边缘到边缘功能,允许内容延伸到系统状态栏和导航栏区域 + EdgeToEdge.enable(this); + + // 设置活动的内容视图为activity_main布局 + setContentView(R.layout.activity_main); + + // 为id为main的视图设置窗口插入事件监听器 + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { + // 获取系统状态栏、导航栏等系统栏的插入区域尺寸 + Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + + // 设置视图的内边距,确保内容不会被系统栏遮挡 + // 左内边距 = 系统栏左侧插入区域宽度 + // 上内边距 = 系统栏顶部插入区域高度(通常是状态栏高度) + // 右内边距 = 系统栏右侧插入区域宽度 + // 下内边距 = 系统栏底部插入区域高度(通常是导航栏高度) + v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); + + // 返回处理后的窗口插入事件,允许其他监听器继续处理 + return insets; + }); + } +} \ No newline at end of file From 865741017f53591a7dbd7d558d2eeff9ac40dc8a Mon Sep 17 00:00:00 2001 From: Wang-YYu-Lu <1756892659@qq.com> Date: Tue, 3 Jun 2025 09:17:24 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=B4=A8=E9=87=8F?= =?UTF-8?q?=E5=88=86=E6=9E=90=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/开源代码质量分析报告模板.docx | Bin 15686 -> 15332 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/开源代码质量分析报告模板.docx b/doc/开源代码质量分析报告模板.docx index 110331ccf9157f70f143812eaf7b4c10d1d9b14b..d009eee8c22234e41d01610d9c86ba7344f97531 100644 GIT binary patch delta 9342 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%0DY_1 zqt1b-@zO>+SUlqagM#~uIk^jGUt#g=9rB;*E9i|MzvhOP6b5=%&kBbMBw8hjj@=BtNnypPMv!_-t> z0=ywT?49eZsm(G`g2mL8KtdE;kF60_V2?R9We=6WaP~mucYdZj)h-16zhA~|cyA#B zQC4*Dn-s8PEjXx@#Q7`(lPo)EWKi&+wJ3Cpyy}Oz7O6#15a$k zo4VwZYIN~~!@fKbRt#5e^b2Pct^+RfCN{^5F^HkhyvE#@V)vdfY3w%6qokg)cq-$F zY|e%V!A&~K#!Oh3CS!Qx%S;Fxe8R{x;$$xnjfe(HR(Dz+`_ZP%u;H_4`TdA3wan02?NmVn zjF%wsKmKq#$){}Jyc0$3e(7fbFTR&eFmNP(!eD+v9rXUcP)qzew^bJ&5KtiFHk}PC zdW^%MYm-=@oYM{t@R2$ptcb&n!PMr2Lj|K8*&ew$ziv-k8W2KYqh=#sWB;s(tqaOVzmF?Qa&zd} zSpUi7ZOTX&yToS4gYGXxh|gtRgXFOVg$YUiXb?l5_S~;Za4#IDr8b8HDrKbrdU#Le zbbEgF)+%hHc1G$Z71?LDv_K6$C&~$nA$MC#B~2Q5&QiGvM=LNn-`@7j-Wzf92$ox`Lf+ZC zx0pPniZpa}AVwTnDe!-I&*?9N$}ZXNh{3P1VfzgYG0Fjgu{C5+=M{5Y?Kf;ge-*Qz@IiD~@85HQ8j}^jz9YoI04H3)^ z(&J|$_)j?W@1)d!jM71Q{FH?MI$MxnU}qoId5nKS{%_En&!8RtFAy#?AW8vB!vC4v w`VUS&I>=mrg7ANq`2V9Y0R_qx;0G52tqbr#*yDhFad1E^f@m<`xc<@kUvKD;B>(^b delta 9693 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
AiQ#NwmM-Jl(9WThbHH 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 literal 0 HcmV?d00001 diff --git a/doc/软件需求模型.vsdx b/doc/软件需求模型.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..c5acba65a2947285dbe75db054a2b9e316f68fee GIT binary patch literal 22217 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 literal 0 HcmV?d00001 diff --git a/doc/软件需求规格说明书模板.docx b/doc/软件需求规格说明书模板.docx new file mode 100644 index 0000000000000000000000000000000000000000..5b486cfd39ebdfa12e75caa0f312582d25a27b7d GIT binary patch literal 20020 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 un7G%Gh1w0 Date: Wed, 14 May 2025 16:31:42 +0800 Subject: [PATCH 04/11] 2025 5 14 --- README.md | 4 +++- doc/开源代码质量分析报告模板.docx | Bin 0 -> 21511 bytes ...开源软件维护方案及成果模板.docx | Bin 0 -> 21749 bytes doc/报告文档00.docx | Bin 10107 -> 0 bytes doc/软件设计模型.vsdx | Bin 0 -> 23678 bytes doc/软件设计规格说明书模板.doc | Bin 0 -> 53248 bytes doc/软件需求构思及描述模板.docx | Bin 0 -> 20583 bytes doc/软件需求模型.vsdx | Bin 0 -> 22217 bytes doc/软件需求规格说明书模板.docx | Bin 0 -> 20020 bytes 9 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 doc/开源代码质量分析报告模板.docx create mode 100644 doc/开源软件维护方案及成果模板.docx delete mode 100644 doc/报告文档00.docx create mode 100644 doc/软件设计模型.vsdx create mode 100644 doc/软件设计规格说明书模板.doc create mode 100644 doc/软件需求构思及描述模板.docx create mode 100644 doc/软件需求模型.vsdx create mode 100644 doc/软件需求规格说明书模板.docx diff --git a/README.md b/README.md index 576c717..576ec76 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ -# test +# 小米便签代码泛阅读 + + diff --git a/doc/开源代码质量分析报告模板.docx b/doc/开源代码质量分析报告模板.docx new file mode 100644 index 0000000000000000000000000000000000000000..626edee6bb8b8a9a5b587ee52f726c15ca9517fc GIT binary patch literal 21511 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 WH!E=91GJA&lp!6sTcyhn!~+1MwC$S! literal 0 HcmV?d00001 diff --git a/doc/开源软件维护方案及成果模板.docx b/doc/开源软件维护方案及成果模板.docx new file mode 100644 index 0000000000000000000000000000000000000000..0b7e6eadd93ea2334378eab53576e07fc0fb462d GIT binary patch literal 21749 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 BXbS)U literal 0 HcmV?d00001 diff --git a/doc/报告文档00.docx b/doc/报告文档00.docx deleted file mode 100644 index c1badbf491a9bf57b4f36847a5c6a6263476dd31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10107 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 diff --git a/doc/软件设计模型.vsdx b/doc/软件设计模型.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..c93266f697d3de1e45c33d335942deae1fd8fc9b GIT binary patch literal 23678 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 PDUtxfC?Jb348#Kf(i`Vt literal 0 HcmV?d00001 diff --git a/doc/软件设计规格说明书模板.doc b/doc/软件设计规格说明书模板.doc new file mode 100644 index 0000000000000000000000000000000000000000..1b04b118913ebe961f4d2748072c0a1e103496bd GIT binary patch literal 53248 zcmeI52|!g<-oVd$k4u5Yf;KL`Y2uR}gn|K}9mOm${W%YF3V! zpEXT2jZ;qhWM$bhQ`StGE#GA8^i5_|X4~ZZe*gQpaNgrRd?XsqaP-H$XTAS({%5=Q z-Fwb!`&%5k^N+C~C@+($Z0fkHi3-u&Eu0I6X|9x&6R{t6xm<2Xr8sRgXHW_JjI6Q+dU+4!HLVvgjQsH7qg8`5Z z10e$j!C<%qGGPb|g-c-=Tn3{c8-_y;jDTFogUewYNSheV@d_9NV<8`|gaQ!%@f;_> zM3@AVp%98d{7;7&p=R@MKDrpBW^tUW7IXE$O=}fg)#fck3u$6CB0ud;LW;7=R3xUQrR%Ul-vR}lYbM8YY#z+A|#q?xXf2mIiKYY>ho{BvRWi5xvG?x&pgZht-O8+PJ!lM z!lrCe9y`_30=`eUeC0_w5{| zUiIN9V@d``8CQmLl(8kBql_<;Im)$WaFj7-K1Ug6?%^oc+r>r19z>!YIm#Gwec`0y z*4KQO8|zxUovCmqJ^Q0H= zH2Xzqds2ow`6I_q_#<&;OudZWa1uS^Y&8#xj9xpNW0B!rNS@5z#2uF?Cp7-_FS1(S zeC5rpJ=!(D`4;rw?S}_4a0~Ww6J2iv$+MJECSb~k^G9?z8YE9MKJk8aFDdbn8$x}E^);;KxC6^W6I^)axJ;G#NSnE z7dNR-mr_5nsWDR0lNlK%5i_0RRB|zy8B!rWVkEA}GKATK%$t14FZDJF33~CjJF}HU zYK!17j!D#qM59iKjyu61(&~*%UuHAu{7d9)05h3nTvLeEm-8e_qZi@CHqZz+0GA}< zW{^VNjDvEWzzk%DG4rTfTnQaXuBDu%ETmTww-cEx0(6%QV=}nx@!!XiWpr?mXm}O&hM8MD5AH-W!|g)^?P7+rG8{b@Z$2_4VWr-}Q`IwXzA- zIA-`Bw}*&lH0U@c?vd)!+)H!!8tvQdUHvyGtaa5qLR^ESQ^!bO?#sAb(j&NyzjM=n zr@ETc3T{2jqv_-CIGm;%$u*k{sJ{FP&0x^o$UOmh?BH>W9ILSm&HpP}oO z-q)Xb3(qk$fkafgk#wFv+nw(D)Ntt$0ySlH6>$WPq5O-9xP!uye&%ZAk-Ms2+ia!W z?yE;3HgFqwTRo;%TT)!gxbtdTTcFeAw}9)&XnCfX?bJ&dAsbD@Dgmns*LtmnC0nC3 zXG#fF-!Ju7<{eY2GVhc!s_vBf^As+DIjj5?{|KM|^fV&W>~+Voo?3I~n&(#aFFv{^ zvZyG_cPww$PYOFuiFKK-;l@4P!Q7)oD{{Zi-L>ZOaS>`=!FRc#O57x@`|RvA3&`{|nJ$M2t1u`X1}JzgmHpJ)2N2=0}Slt}JdQvP||p$z1h&z#lH6VycRE_!kl zmtx~@DSu;(u$erC9M0Xr2;*)vi~Ac1HG{vMxkJq(g-OhalH;bdy zIJLTokcq)8&xpVkDI|1fsK+PX+1@#;q!x31k~)00%Ctx5Y`KDA<9T_lpY^&?TT zRzAt3Dm_bGrIC2`BTX+&nqH)O+t?vlbtxB#Q$LcVXp*Fm>a)4F@{Aj9Ev$<)60d%w z>0K#J5-r>8pYL8eZc1IG>0NKq^r@1@-NH?Yj+BHJug$w7_pA|hk*kj;SFe-mdHQN{ zNt-q0a+XM0t<4+0Ii*gL^{pq#dh^W3-81*p^cQ#;N&M=XbTVbsn;zMeq*`~m**}&2 zeW`PbjQVwvO7EplPAapP?#Y-Tnu}l1d*ZMK6K|=jM0!tsauS(6wMZnrZTx~Y*&