From 74b6897a12ec603ef835aaa77a01f0c32f49aa1c Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" <takaoka@google.com> Date: Thu, 30 Jun 2011 10:09:21 +0900 Subject: [PATCH] Adaptive suggestions strip Bug: 4903845 Change-Id: I9e2e17a9eee72df5c92414dcd4796ed7fe1655e1 --- .../btn_close_candidates_pane.9.png | Bin 936 -> 0 bytes .../btn_expand_candidates_pane.9.png | Bin 1123 -> 0 bytes .../keyboard_suggest_strip_divider.png | Bin 2946 -> 0 bytes .../btn_close_candidates_pane.9.png | Bin 713 -> 0 bytes .../btn_expand_candidates_pane.9.png | Bin 681 -> 0 bytes .../keyboard_suggest_strip_divider.png | Bin 2812 -> 0 bytes .../btn_close_candidates_pane.9.png | Bin 1027 -> 0 bytes .../btn_expand_candidates_pane.9.png | Bin 1350 -> 0 bytes .../keyboard_suggest_strip_divider.png | Bin 2951 -> 0 bytes java/res/layout/candidate_divider.xml | 9 +- java/res/layout/candidate_word.xml | 5 +- java/res/layout/candidates_strip.xml | 88 ++-- java/res/values-sw600dp-land/dimens.xml | 1 + java/res/values-sw768dp-land/dimens.xml | 1 + java/res/values/attrs.xml | 4 +- java/res/values/dimens.xml | 2 + java/res/values/donottranslate.xml | 7 + java/res/values/styles.xml | 10 +- .../inputmethod/latin/CandidateView.java | 430 ++++++++++++------ .../android/inputmethod/latin/Settings.java | 2 +- .../inputmethod/latin/SuggestedWords.java | 19 +- 21 files changed, 359 insertions(+), 219 deletions(-) delete mode 100644 java/res/drawable-hdpi/btn_close_candidates_pane.9.png delete mode 100644 java/res/drawable-hdpi/btn_expand_candidates_pane.9.png delete mode 100644 java/res/drawable-hdpi/keyboard_suggest_strip_divider.png delete mode 100644 java/res/drawable-mdpi/btn_close_candidates_pane.9.png delete mode 100644 java/res/drawable-mdpi/btn_expand_candidates_pane.9.png delete mode 100644 java/res/drawable-mdpi/keyboard_suggest_strip_divider.png delete mode 100644 java/res/drawable-xhdpi/btn_close_candidates_pane.9.png delete mode 100644 java/res/drawable-xhdpi/btn_expand_candidates_pane.9.png delete mode 100644 java/res/drawable-xhdpi/keyboard_suggest_strip_divider.png diff --git a/java/res/drawable-hdpi/btn_close_candidates_pane.9.png b/java/res/drawable-hdpi/btn_close_candidates_pane.9.png deleted file mode 100644 index bdd949577df94729947f2afdd78face65e669ca7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 936 zcmV;Z16TZsP)<h;3K|Lk000e1NJLTq001=r001=z1^@s6;pU@o00004b3#c}2nYxW zd<bNS00009a7bBm000Y#000Y#0XNCZtpET6N=ZaPRA_<in#*rhRTRd5ALV5*$itW# zvBaq)Mg~ZO!hodu2RJcm3OZ=gk{Co1V9=2c97qEp0pkekbK=CI12Fia)dUlwP9#l$ z2;pTx)P|<{9CV#_TYB$3=k_+xd(W5b^xOOHwbr+@*S%-&b&72OM_b4+;8@RsU(8)t zbgu=JC{dzBiAF*5;nennK{o)825$o<f?ooD0g!aN(czo&In}V8vfUZ<Wngpgwkjss zt_=a70!TXD2q|+~l<hS^`+=>&ZvrQRe-DfV9|x8Me*)MNd^_+^@Na;(0VLh1S5}#R zDQrIu9F6WHz+mv>lKw8>X9ch`y4}E);C+%V)FZ9%qHM1WdK_3Ce7~fjIt0x0y%~5n zx_=Ujm2|6!n=<_XY#$8zEYJ%e=}e;p+1?oR81P;Af2)X#q5(T?{}ipKka0oS?nz>G z*0z{7ZOZg3x~Nxx(P$s#F|fTZTEFdf+wD1H4JNT(Eh2JpPGQ+u?it_<07?JmuzLy^ zi0&%jxftIq>9=aOlE!R*72Ovz4SCLrEuDT(Mr#9xqg90MF56we`%E5>#(~2TZxQf; z?QOQV)rgzLYD+ZKM6UD$)+PLWwTZT01Nx$S4%iJK>9XyUF@6|$FXj(O`n-a>G}dD| zwKiw^<=v^J37_=`!uCr+ck%!8+tg`W(#4qD3w#{Idu{&{pMN>SZ5nG?POZ5YHJ0$@ zGe5NbJn&|8F9L5s<?Dl_E4H%~Jp>#GKckXPB~u@$prI;SI{p4g`1<%el8l{Y@`4BO zj-=6A4ki5#Q$H;GV))k?(>f|>sEWLc${v&xz^33|Cju`4d-DcOA?a!r+bq^ZqM;^Q zH~l321z>v!cp>-^Nx8qgMPYk+77O?>(~t*6cj_}H&v2`lyn4?kx|3L+6ftbw^vfXW z2iw_m<aOJ_G5&L-1lfK%^ADWL;ug|bN6^^{FMAqsrH`w8c2y}0FDd3y_v>J~?)Na$ zb-xemsQc}RZZ~i(c%P)IH-bto=UR4N8?>Le)iSrT^S4Zwov+s`t4zOYXqvYk6}`^> z(rqblC-{86bZgFsZ;28mO0+J@e_~t+kZq)z2aEe*H*=kSZ1W#A%1oeyR*5|T0000< KMNUMnLSTY*-?b<J diff --git a/java/res/drawable-hdpi/btn_expand_candidates_pane.9.png b/java/res/drawable-hdpi/btn_expand_candidates_pane.9.png deleted file mode 100644 index 63015ec5bbd67239e9ac423c755806e59dadc97d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1123 zcmV-p1f2VcP)<h;3K|Lk000e1NJLTq001%o001%w1^@s69zTe&00004b3#c}2nYxW zd<bNS00009a7bBm000Y#000Y#0XNCZtpET71xZ9fRA_<inoo#Tbri=xM{BgQvce34 zYKn=-nnj@5%wo!E)glVPHf<&a0|^rfGDvV`6odxR9~v!?7Da-(FeoTzm|odH<SLn{ zbW`9)$4O<%zAf%~&966i?*0AldoOzNzMJ2@=bm%E=iK|={hf2(LlS`KT*!0i=p?%6 zqKhs%6xL4Xl9mHKemZMrXWB*8(nKWP4m=F32Ks<y4JtFh6z~o3nVJ3AD(aRbB545F z1oS7G9tTFvY@*o^no2~{O~7_wFc4n=YQQnzXW%!NUj^I-tN|VXt_W-<fL&(xYt>LH zCn9ML@G@|Xi%tP=0biKeY>90T@F4IsaEptlffvl|Se0-p*np&Ul4_DBB~3_rLek<2 zeipm!g!`&VT302cbPH)!Kzu~fstUw;K92-9=I&G%se~&6!o!kQCK49;Ug<vTH)utQ zc`Dg%CmNU3n-*%6|6cb!DQS0#X$r}p6HH24pB`p3&-#F8u-qauTa>`D(bp5efwb_F zZ~*wefwL4*iAd^WZnGOTv$l1W?t7n~_Di}m#xC}WJml*cU@S4VDmdy~knK06h)ra* zuQfCKqw!)hZ!bwVHp-l%*1%ne*hKn#J)RRtKk%`nkw{;4JCpP*@R6iDa#ZSEeL2_W zp)?UM#p_k<$sCnufTh3|NjqY8cu7mh%9|(2YOu{YYIUw<9z!8wp2*d~@!6c~+sFz; zfJcGXB{i1se?!uBz}vvEi;e<2a#W`mh#?m-iTqh~(adImt-xUy-4E>Z%J?7fP4qqB z9v6K8Ja1+fb6kgS#=;mNE|Hnw_}V-LGyC1lb^>pD0KLHbVI3yvKHy#8X5bR=ikZD; zW(x%wa-Ay+vNRDhJIh=$x0dLR0xtoxzzx7Vl7=Kb0=(hDT>zdlvkyzC>s&KtHeIMm z{99|v*L%wp&Fm9k3)%N+3Ggbg6Sy2W4Qw*A@d(a3*HodFBQ}vqUk75|N@n&gFhbUB zEg~Co`~ZxY*@-fHNtXd@8@LM*o5-iWE(eBU49x5l@D%VJ@HMb8p_Ls1uJ_~5BW>a! zX|GqL`=$66SyE3*_vjnte&^a7YnD>|)}7u3JRWOgX0v8?DS_uP=Lk7l3rTzYPK~v( zu^MxZJt?NCL}9CYFtHtt@qO@LX?2}296lUs#gp+TaVQu*qz*JHkAsGTanQJ=4NZ)L zHUuB1nxx@!%lWRF8PKf-b}?7bog^y;QwDUKncKn70o%>&t198NVr2RvFc65tk?Bvs zd6!>FR)gh@Our->nf_8WlvWL~2gwEnojJsw=dII!R#?z`*4Zuf(~E8Vp{I*3y6B<< p@xS<+lS#s?a69=gBw8Gx#9ylpY%_ild}06q002ovPDHLkV1h{^|G5AF diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip_divider.png b/java/res/drawable-hdpi/keyboard_suggest_strip_divider.png deleted file mode 100644 index a62daf90c49f7e80643f672fe5beeff96f8c00e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2946 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 diff --git a/java/res/drawable-mdpi/btn_close_candidates_pane.9.png b/java/res/drawable-mdpi/btn_close_candidates_pane.9.png deleted file mode 100644 index 5ea56925dd62dc57218671ba37c00519e59efe6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 713 zcmV;)0yh1LP)<h;3K|Lk000e1NJLTq001KZ001Kh1^@s69@(>500004b3#c}2nYxW zd<bNS00009a7bBm000Y#000Y#0XNCZtpET5Ye_^wR9J=Wm_2AyVHAd+qgW&TvFM`M zMjWjm?NAd$9R%&Bt2l^Ril&ob2Zv6AlP!o2;-rYWb+J<s9sHrKZlaSQNYPSJ6a|A) zUWa>v*Ld&k%}q)i@-83bp7VZBa`?V;Zjb~ZS}Qq6%R$;|E3+(XqNFZh53n6r53B$m zfLCVrJ&R@CFp`SENub~mwORq@fxBilw<a)>wg3~rLEtO!5O@Z>1%3e=fL*|T;4rWm zcnn-Lv(IU^NDI<0>As|SNn?^aSBdZRxOva(Zwid09!b-Z9!V;sqW_ay@VseBJ<Wib zlr$%4s2-3|{*dQSHUuN7DCvcy(JUY#pHcTIHUe{1(gR7G5@Px!O-S075R-GCYf0O! zOEBmH_5rhI_9G@{FK`n$4&0KoJ1Wl1D!?o-?7oqTg#iW#?vaHUkR!l#f@6Kfy>3W4 z6yvwxegj!x`h0yC0a5}k`LmLl-3Cg)GH_Yai3q={&yFlG9lrimBHw5X_z0BEYze^3 z7J;+C7vQ|4V>NzNpN&~yD!%4IAV-07z#?#__GUG+WuOc!0T*gYRy_n2Vw42)-q)R> z&t4K-@u$t~pYl1-8-kKO1zv|9<!gM?OH#LA=i_xJNBfPtUw2$c>@Q<x-w3+zh@@Ox zTuP7}FakVx-$*5u3E&>k3!G{M#`AlDI}N!=n)2Q<m@$9Q^QTq|O=A}B+I2NcZ<5XH z+HRVcG~?f}oN}Hid;E-~d{TTht)5A5E5W39fb^5z6M{+aQ&V9=P_3VVBcQ@>2OYpq v8hblvtF27>Z~mV#Nti_*s<ncQ-b~^*d#IM&U=wKY00000NkvXXu0mjf)}J;L diff --git a/java/res/drawable-mdpi/btn_expand_candidates_pane.9.png b/java/res/drawable-mdpi/btn_expand_candidates_pane.9.png deleted file mode 100644 index 83cb653055a39c24b26c65458a6f4f779d89cdbe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 681 zcmV;a0#^NrP)<h;3K|Lk000e1NJLTq001KZ001Kh1^@s69@(>500004b3#c}2nYxW zd<bNS00009a7bBm000Y#000Y#0XNCZtpET5OG!jQR9J=Wn7vDuQ5c7>Q)GspBz;i| zIogm0eno*a6b(&n{Q(X(J2q6%ra@V@WLq@3Xao{D6r$qV9JDkQ1VK{B)!=PCyu6>! z`-%<T%Yk!#_wQUU&wK83KMyK^>}?nvdk(T6`;j|R-bA$(I0u{p4gy=i7vN(`=|>*R znqkxt;1)0(5QVV?tN|}mN~^m9qaFqB0GEO9z&l_C_yqh04gqI@i@+7219%VIPbqz? zW{YY;y43}BO}(wQRM5ACZY}b<8v>)YtMlrzI$Ra~zue)-n^)T#0W+npsspuvWby|h zf2uARbwu4z$Mb+>e8$6Pq#l^Z>Ra_loiNSeGgD4>po~E)Fa#{6lz!F&lTz9QmVm+V zEgB_ZfIhbC$a)6wn0mLIVdy&5dum5!dOiI5^1z&l@pEQw2)GW+sV7T-^Z;|fHQ+*K zX~*Yu9+;*W|30FW(re%u&<o6}Z3Q5mz*C?Hc$iXJ&Mfcv9L@u?8Dn$7{0rbY&<)I} zT>)|&m<3J%Pf|*+3i5Ui!6vnaIuyroti<|_s2>aJP4$hsqFybb9}B;sQd^dTX^V0` zSw=G$6?P+z?)fs>$?$6{B`FCL29IKs!bg?W^r{ca-9OdVnMyFD4X(hWxnaU+I{q8| zIYIg(f4Y*i8nf)JUDIV5mt^B^?J(_87vmRBRN2o=gnls!Va07~>GZnT?({BEeW&+< z?N0A&Lt!#dd*1^Wfy%xeGy%V;@9khe_9IvPH{WNHN=ii!)owu+-%R-fAJysIiKm53 P00000NkvXXu0mjfeu65S diff --git a/java/res/drawable-mdpi/keyboard_suggest_strip_divider.png b/java/res/drawable-mdpi/keyboard_suggest_strip_divider.png deleted file mode 100644 index 363936362f40906afd59b09cdbcd70693ab1b004..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2812 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 O0000<MNUMnLSTX_t2HhF diff --git a/java/res/drawable-xhdpi/btn_close_candidates_pane.9.png b/java/res/drawable-xhdpi/btn_close_candidates_pane.9.png deleted file mode 100644 index 9d797ed0d25a556ad6499dde6f4841fa4024e9aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1027 zcmV+e1pNDnP)<h;3K|Lk000e1NJLTq002Y)002Y?1^@s6I1`hy00004b3#c}2nYxW zd<bNS00009a7bBm000Y#000Y#0XNCZtpET6rAb6VRCt{2oJ)vKVHn5%k8zFMQ!>aB zB^E9*Qi@qwDapcZp=L;Kg=8TX7Kju@3At@-WMzTIeJm)sEJ!gS*I`^H(qrNO*7=_K zX1?>D?|d^f&#&}<&iUT+yie1=bI$vmH&9goQ2y(#C;;W(qFetV+R&q`3ve9AaU92S z{vw?@nW_$8IFUM%T1EX$eNBA`03!0W^3?$V)ZbJM6?KTJ&S1ENI-OcoWOy-xWA0GT z0Dy?xF2A~>xI-+tIz&~6GTcs`P5n&0Oub2cPW?sgMIA?-Nu5g_M7>7c2>>GUF?-bo zxI-+tI7C%PGdx5cK|M)54gezZEo1)v43|@vQr}YRng3;${K=`@A%?OXqN)QK9;XhW zZUF!hxnr-%162)AtKHO3)a9J_OV-rx5JR~R*~@SiwGIG8<X$;>Bj%sN@G$iT=iit$ zr8~sXGs{JZH_$oMBS7alBM|0O)nh!hDp_BaH(GayA=5oXRSz;8Ph9{2BJv|LPc_38 z)T7MvCNfW7h8L+%m}gB)9{4?^Em8N7L_cF1^*oTt8Iu_9qYkFl@b`7h`#4QL5ozUh zmw0Mnvfh|}iaW#*`;?hL4gHM9n2S|)9>X2funImv4QrGm9KQ_!M5H0*6rr9)rry+b zx<d@H4yiWBFVbA3s^KY8PklxW_lh?hcZKJJWA^a;K8`zAVk%qDs5JE@afcXU9n#wz zcldNs)x``~Q*HmEpwlHHO}ws-r%q8f@%(p=yU@;*ww^v6)mIF6h#}S?t>(CIu|cXj zpW%9H6Ll?6x(6yEZ<#0DbM{lW@_aML*{4sx67`nE9b$-e$SZR^mipYBe?Sf0@m&BQ zBF!<AiO5r+;3>74`ly{t#+YMUZ%N!ChFFJ$wMF=%HkEocIY>mpx7khE$|^)e-lfbJ z>IwCwS_>s{hZv$9A|fpSpsJypUd!Wy{5|@vo(GA3NG<g)>uHJ2<qk1q>Zt-aOAVc~ zf>ml45athkmD5=hxkC(@93mpO06<m4o8n3yH}d!Uxl~sIRh^uiA3#I0zAU&y43+w} zy8)=&cbdc(yU>&MZ@ZNuul*rm4H5Q-45x<uAt!)b_J=H^hNsGVYUr<|>fm)Wl{>_c z_a3uh48tC?8fxBq%&t?z9<vYGt1iGDV)1>dg}6g3|H@wX(9Qoz?W(=*{-)|Uj^j9v x^Dp85e@Fs<Q#FXHLL~K)=6`cj)LKnd@duitF@F+Wuu1>`002ovPDHLkV1n-o*S7!w diff --git a/java/res/drawable-xhdpi/btn_expand_candidates_pane.9.png b/java/res/drawable-xhdpi/btn_expand_candidates_pane.9.png deleted file mode 100644 index 88d01c9c865e1a60a93ca404e9e8489bce70199a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1350 zcmV-M1-bf(P)<h;3K|Lk000e1NJLTq002P%002P<1^@s6j`zt$00004b3#c}2nYxW zd<bNS00009a7bBm000Y#000Y#0XNCZtpET7=t)FDRCt{2n_q|)RT##9PnKG3rG@>I z{#Y17C>Us_LZ#gnb)#1WT4oU98X>t*P!JU=Y+a?KQb89<UI#_xpKYUrKq#^zOEL>@ z)HKc9o-XE{zH!?9oSARdO?Dm_&YUynyzevbcg~q}-uHai1~8)&j`tt6258WrL4yVj z8Z<a7G*XIfPXNYdicU#7JQ7sSi4kny0^A48ilV7N*C17o0pG>_7r=*-ei&|g7Ywt4 z^8&-x6Ku}~9*gXZ4n*yVbd#jM&R7kKdWVDUYvXneFfaG`1kfM%p94Pv$1~3_1#Sjr zNB%D0;+%{=;3WV_zt+K-I*nj^Ht=#}FOPJ8q^|>?NIF$Q-dNxs;E5=@G18-vJ|pS# z%7injnmM5^*j`|}-}dgf`fM+@J;wH!4rPytYjMa;b@ba_PzU{vhJ)?f<8~u34mcF~ zrzL&WiR?D|)<t#_@F%bgK+@M$#a1?g?Mc8}8A1n%uYsiBs>&^(_nNqU1GtWs;UAH7 zXz*6;MK*H+9jp^<_X6`HdxGSb*jEdyV*00$^u+Wtx=T`b6;YLXg6(;<3;@u3E)4(> z`g$`(^MhAuR2>eFM!GkyZ58EoifzC*aY2h$DKv8eaABFswx`Bzx)<04AZbKm7m{py zOJrXGX4t+ho_$+XPAMY*_h#-713OB#9}aAf^e`}iWT_2M*a&5Z!z@}pfqqG+C7m9u zV&;2Z3v6FKSb2s+x;e{oEQDrGpu7>L#s#f?{(oS52JoKkCAODTC1+c<yKQ#^TW#Ok zrh3XJ%drp&&k5lZ%(}#WYEyj$Fdld^+TH-XC~2UCzHz_{z`{)Na$xlkO;SExDc_<# z%Q8LTvRwX1o4Tt=949Fr0A91*WqUB+;=iyx(e^}O17{jwJMdharbl!6Jl`Qv=Iiix z(Tb9e*<K0sMA7}goxm0V+bah148>A7T?I~#^qok1CAH&_|4bL=+f0m<>j}ql`77F0 zmh>0!Jb>+=N!(;p;_;idpUV0iY~KN_&Bz@9)=PS~Aiq4H-wU=YZUjk3Y^R3k0&e2W zao?`(Cff&Sjp?g^jkbG89IOD(0vD0&NCA2z?JUYK_(1$vlJaxJkSM!iOamh`f$6~3 zq75azZ##9itRwm5*3#O}i^M_F9rgE?<TgFWu`rrBf$}|Jcce3cxv3Mi==WdJmjJPV z>ZRpI2lyW7E*np<oxa1I9LK^aYlIIXT}HB5xjXV7l@TIozwM>Kdf;Rfua<PYO|zkp za=0?mkIM?E<X*GAnPfYiIx`-wvYn0q%K#MbO}X|0-j3`vV2`AwWyLge0@WwR&5=%v z>!B(_B%P8pP^A|H9?Wpa@+yT&Mv%0NBsiL)JC?lX454pTrl>D?l}4SxmjkqdFI9pd zW%NQ4e3?uWe5nU@$0C1;{L0~oL&OkxHL}-}#3COD=pgo4kCWK;!dz5(r|m^GN2M3p z-jRz+FFd=1v#Y4{kj5P16bUVdM(XX^K=nf!%cCgWAf>y*HIhE7OgN*enG>k_;8y0$ zQV%dU_c(uMX&>-M=J_Qg{)TpEmOiC*X6ax(tcUR&V+2Rj*x=|ny*8wl<}l~~A0vIX zd3>hm<OrQ@ZqT4Xg9Z&6G-!)a|F3!3Mk=&$Jl~8}?4@k}0Y8Tj6yA5+)&Kwi07*qo IM6N<$f=SVNC;$Ke diff --git a/java/res/drawable-xhdpi/keyboard_suggest_strip_divider.png b/java/res/drawable-xhdpi/keyboard_suggest_strip_divider.png deleted file mode 100644 index cd7c2c7a2b4cc5a482fc5fb7a1a4297fa1d37b0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2951 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 diff --git a/java/res/layout/candidate_divider.xml b/java/res/layout/candidate_divider.xml index 7481630745..a1059dc2fe 100644 --- a/java/res/layout/candidate_divider.xml +++ b/java/res/layout/candidate_divider.xml @@ -18,12 +18,13 @@ */ --> -<ImageView +<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="match_parent" - android:src="@drawable/keyboard_suggest_strip_divider" + android:text="@string/label_candidate_divider" + android:textSize="@dimen/candidate_text_size" + android:gravity="center" android:padding="0dp" android:focusable="false" - android:clickable="false" - android:gravity="center_vertical|center_horizontal" /> + android:clickable="false" /> diff --git a/java/res/layout/candidate_word.xml b/java/res/layout/candidate_word.xml index 7b6db2fe8e..b711e8f291 100644 --- a/java/res/layout/candidate_word.xml +++ b/java/res/layout/candidate_word.xml @@ -18,16 +18,19 @@ */ --> -<Button +<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:minWidth="@dimen/candidate_min_width" android:textSize="@dimen/candidate_text_size" + android:gravity="center" android:paddingLeft="@dimen/candidate_padding" android:paddingTop="0dp" android:paddingRight="@dimen/candidate_padding" android:paddingBottom="0dp" + android:focusable="false" + android:clickable="false" android:singleLine="true" android:ellipsize="none" style="?attr/suggestionBackgroundStyle" /> diff --git a/java/res/layout/candidates_strip.xml b/java/res/layout/candidates_strip.xml index ea6708ee72..0f542c0a25 100644 --- a/java/res/layout/candidates_strip.xml +++ b/java/res/layout/candidates_strip.xml @@ -25,73 +25,39 @@ <LinearLayout android:id="@+id/candidates_strip" android:orientation="horizontal" - android:layout_width="match_parent" + android:layout_weight="1.0" + android:layout_width="0dp" android:layout_height="match_parent" > - <RelativeLayout - android:layout_weight="1.0" - android:layout_width="0dp" - android:layout_height="match_parent" + </LinearLayout> + <LinearLayout + android:id="@+id/candidates_pane_control" + android:orientation="horizontal" + android:layout_width="wrap_content" + android:layout_height="match_parent" + > + <TextView + android:id="@+id/expand_candidates_pane" + android:text="@string/label_expand_candidates_pane" android:gravity="center" - > - <include - android:id="@+id/word_left" - layout="@layout/candidate_word" /> - <include - android:id="@+id/info_left" - layout="@layout/candidate_info" /> - </RelativeLayout> - <include - layout="@layout/candidate_divider" /> - <RelativeLayout - android:layout_weight="1.0" - android:layout_width="0dp" + android:layout_width="wrap_content" android:layout_height="match_parent" + android:minWidth="30dp" + android:textSize="@dimen/candidate_text_size" + android:padding="0dp" + android:visibility="visible" + style="?attr/suggestionBackgroundStyle" /> + <TextView + android:id="@+id/close_candidates_pane" + android:text="@string/label_close_candidates_pane" android:gravity="center" - > - <include - android:id="@+id/word_center" - layout="@layout/candidate_word" /> - <include - android:id="@+id/info_center" - layout="@layout/candidate_info" /> - </RelativeLayout> - <include - layout="@layout/candidate_divider" /> - <LinearLayout - android:orientation="horizontal" - android:layout_weight="1.0" - android:layout_width="0dp" + android:layout_width="wrap_content" android:layout_height="match_parent" - android:gravity="center_vertical" - > - <RelativeLayout - android:layout_weight="1.0" - android:layout_width="0dp" - android:layout_height="match_parent" - android:gravity="center" - > - <include - android:id="@+id/word_right" - layout="@layout/candidate_word" /> - <include - android:id="@+id/info_right" - layout="@layout/candidate_info" /> - </RelativeLayout> - <!-- Image drawables are set in CandidateView constructor --> - <ImageButton - android:id="@+id/expand_candidates_pane" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:visibility="gone" - android:background="@null" /> - <ImageButton - android:id="@+id/close_candidates_pane" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:visibility="gone" - android:background="@null" /> - </LinearLayout> + android:minWidth="30dp" + android:textSize="@dimen/candidate_text_size" + android:padding="0dp" + android:visibility="gone" + style="?attr/suggestionBackgroundStyle" /> </LinearLayout> <LinearLayout android:id="@+id/touch_to_save" diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw600dp-land/dimens.xml index 5016f4247b..d732c87893 100644 --- a/java/res/values-sw600dp-land/dimens.xml +++ b/java/res/values-sw600dp-land/dimens.xml @@ -53,4 +53,5 @@ <fraction name="key_uppercase_letter_ratio">29%</fraction> <dimen name="candidate_strip_padding">40.0mm</dimen> + <integer name="candidate_count_in_strip">5</integer> </resources> diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml index 8cbd37e174..45a3d40b92 100644 --- a/java/res/values-sw768dp-land/dimens.xml +++ b/java/res/values-sw768dp-land/dimens.xml @@ -58,4 +58,5 @@ <dimen name="key_preview_offset_ics">0.05in</dimen> <dimen name="candidate_strip_padding">40.0mm</dimen> + <integer name="candidate_count_in_strip">5</integer> </resources> diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index c5897c853c..fb99336e87 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -120,8 +120,8 @@ <attr name="colorTypedWord" format="color" /> <attr name="colorAutoCorrect" format="color" /> <attr name="colorSuggested" format="color" /> - <attr name="iconExpandPane" format="reference" /> - <attr name="iconClosePane" format="reference" /> + <attr name="colorDivider" format="color" /> + <attr name="candidateCountInStrip" format="integer" /> </declare-styleable> <declare-styleable name="Keyboard"> diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml index 36074b3b8d..6cf5fe99cb 100644 --- a/java/res/values/dimens.xml +++ b/java/res/values/dimens.xml @@ -82,6 +82,8 @@ <dimen name="candidate_min_width">44dip</dimen> <dimen name="candidate_padding">6dip</dimen> <dimen name="candidate_text_size">18dip</dimen> + <integer name="candidate_count_in_strip">3</integer> + <!-- If the screen height in landscape is larger than the below value, then the keyboard will not go into extract (fullscreen) mode. --> <dimen name="max_height_for_fullscreen">2.5in</dimen> diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 21e6c55c6a..f88d2df1c4 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -43,6 +43,13 @@ <!-- Label for "switch to phone symbols" key. Must be short to fit on key! --> <string name="label_to_phone_symbols_key">\uff0a\uff03\uff08</string> + <!-- Character for candidate divider (BOX DRAWINGS LIGHT VERTICAL) --> + <string name="label_candidate_divider">\u2502</string> + <!-- Character for expand candidates pane (BLACK DOWN-POINTING TRIANGLE) --> + <string name="label_expand_candidates_pane">\u25bc</string> + <!-- Character for close candidates pane (BLACK UP-POINTING TRIANGLE) --> + <string name="label_close_candidates_pane">\u25b2</string> + <!-- Option values to show/hide the settings key in onscreen keyboard --> <!-- Automatically decide to show or hide the settings key --> <string name="settings_key_mode_auto">0</string> diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml index 29b9d589cd..c0cc8fbda5 100644 --- a/java/res/values/styles.xml +++ b/java/res/values/styles.xml @@ -92,8 +92,8 @@ <item name="colorTypedWord">#FFFFFFFF</item> <item name="colorAutoCorrect">#FFFCAE00</item> <item name="colorSuggested">#FFFCAE00</item> - <item name="iconExpandPane">@drawable/btn_expand_candidates_pane</item> - <item name="iconClosePane">@drawable/btn_close_candidates_pane</item>" + <item name="colorDivider">#20FFFFFF</item> + <item name="candidateCountInStrip">@integer/candidate_count_in_strip</item> </style> <!-- Theme "Basic high contrast" --> <style name="KeyboardView.HighContrast" parent="KeyboardView"> @@ -189,12 +189,12 @@ <item name="android:background">@drawable/keyboard_popup_panel_background_holo</item> </style> <style name="CandidateViewStyle.IceCreamSandwich" parent="SuggestionsStripBackgroundStyle.IceCreamSandwich"> - <item name="autoCorrectHighlight">autoCorrectUnderline|autoCorrectInvert</item> + <item name="autoCorrectHighlight">autoCorrectBold|autoCorrectInvert</item> <item name="colorTypedWord">#FFFFFFFF</item> <item name="colorAutoCorrect">#FFFFFFFF</item> <item name="colorSuggested">#FFFFFFFF</item> - <item name="iconExpandPane">@drawable/btn_expand_candidates_pane</item> - <item name="iconClosePane">@drawable/btn_close_candidates_pane</item>" + <item name="colorDivider">#20FFFFFF</item> + <item name="candidateCountInStrip">@integer/candidate_count_in_strip</item> </style> <style name="PopupMiniKeyboardAnimation"> <item name="android:windowEnterAnimation">@anim/mini_keyboard_fadein</item> diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index a5bfea0f8f..ecabe6792b 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -30,6 +30,7 @@ import android.text.TextUtils; import android.text.style.BackgroundColorSpan; import android.text.style.CharacterStyle; import android.text.style.ForegroundColorSpan; +import android.text.style.StyleSpan; import android.text.style.UnderlineSpan; import android.util.AttributeSet; import android.view.Gravity; @@ -38,7 +39,6 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; -import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; @@ -57,24 +57,29 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo public void pickSuggestionManually(int index, CharSequence word); } + private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. private static final int MAX_SUGGESTIONS = 18; - private static final int MATCH_PARENT = MeasureSpec.makeMeasureSpec( - -1, MeasureSpec.UNSPECIFIED); + private static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT; + private static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT; private static final boolean DBG = LatinImeLogger.sDBG; - private final View mCandidatesStrip; - private static final int NUM_CANDIDATES_IN_STRIP = 3; - private final ImageView mExpandCandidatesPane; - private final ImageView mCloseCandidatesPane; + private final ViewGroup mCandidatesStrip; + private final int mCandidateCountInStrip; + private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3; + private final ViewGroup mCandidatesPaneControl; + private final TextView mExpandCandidatesPane; + private final TextView mCloseCandidatesPane; private ViewGroup mCandidatesPane; private ViewGroup mCandidatesPaneContainer; private View mKeyboardView; + private final ArrayList<TextView> mWords = new ArrayList<TextView>(); private final ArrayList<TextView> mInfos = new ArrayList<TextView>(); private final ArrayList<View> mDividers = new ArrayList<View>(); + private final int mCandidateStripHeight; private final CharacterStyle mInvertedForegroundColorSpan; private final CharacterStyle mInvertedBackgroundColorSpan; @@ -85,6 +90,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo private final int mColorTypedWord; private final int mColorAutoCorrect; private final int mColorSuggestedCandidate; + private final int mColorDivider; + private final PopupWindow mPreviewPopup; private final TextView mPreviewText; @@ -96,8 +103,9 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo private boolean mShowingAutoCorrectionInverted; private boolean mShowingAddToDictionary; - private static final float MIN_TEXT_XSCALE = 0.4f; - private static final String ELLIPSIS = "\u2026"; + private final CandidateViewLayoutParams mParams; + private static final int PUNCTUATIONS_IN_STRIP = 6; + private static final float MIN_TEXT_XSCALE = 0.8f; private final UiHandler mHandler = new UiHandler(this); @@ -150,6 +158,114 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } } + private static class CandidateViewLayoutParams { + public final TextPaint mPaint; + public final int mPadding; + public final int mDividerWidth; + public final int mDividerHeight; + public final int mControlWidth; + private final int mAutoCorrectHighlight; + + public final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); + + public int mCountInStrip; + // True if the mCountInStrip suggestions can fit in suggestion strip in equally divided + // width without squeezing the text. + public boolean mCanUseFixedWidthColumns; + public int mMaxWidth; + public int mAvailableWidthForWords; + public int mConstantWidthForPaddings; + public int mVariableWidthForWords; + public float mScaleX; + + public CandidateViewLayoutParams(Resources res, View divider, View control, + int autoCorrectHighlight) { + mPaint = new TextPaint(); + final float textSize = res.getDimension(R.dimen.candidate_text_size); + mPaint.setTextSize(textSize); + mPadding = res.getDimensionPixelSize(R.dimen.candidate_padding); + mDividerWidth = divider.getMeasuredWidth(); + mDividerHeight = divider.getMeasuredHeight(); + mControlWidth = control.getMeasuredWidth(); + mAutoCorrectHighlight = autoCorrectHighlight; + } + + public void layoutStrip(SuggestedWords suggestions, int maxWidth, int maxCount) { + final int size = suggestions.size(); + setupTexts(suggestions, size, mAutoCorrectHighlight); + mCountInStrip = Math.min(maxCount, size); + mScaleX = 1.0f; + + do { + mMaxWidth = maxWidth; + if (size > mCountInStrip) { + mMaxWidth -= mControlWidth; + } + + tryLayout(); + + if (mCanUseFixedWidthColumns) { + return; + } + if (mVariableWidthForWords <= mAvailableWidthForWords) { + return; + } + + final float scaleX = mAvailableWidthForWords / (float)mVariableWidthForWords; + if (scaleX >= MIN_TEXT_XSCALE) { + mScaleX = scaleX; + return; + } + + mCountInStrip--; + } while (mCountInStrip > 1); + } + + public void tryLayout() { + final int maxCount = mCountInStrip; + final int dividers = mDividerWidth * (maxCount - 1); + mConstantWidthForPaddings = dividers + mPadding * maxCount * 2; + mAvailableWidthForWords = mMaxWidth - mConstantWidthForPaddings; + + mPaint.setTextScaleX(mScaleX); + final int maxFixedWidthForWord = (mMaxWidth - dividers) / maxCount - mPadding * 2; + mCanUseFixedWidthColumns = true; + mVariableWidthForWords = 0; + for (int i = 0; i < maxCount; i++) { + final int width = getTextWidth(mTexts.get(i), mPaint); + if (width > maxFixedWidthForWord) + mCanUseFixedWidthColumns = false; + mVariableWidthForWords += width; + } + } + + private void setupTexts(SuggestedWords suggestions, int count, int autoCorrectHighlight) { + mTexts.clear(); + for (int i = 0; i < count; i++) { + final CharSequence suggestion = suggestions.getWord(i); + if (suggestion == null) continue; + + final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion + && ((i == 1 && !suggestions.mTypedWordValid) + || (i == 0 && suggestions.mTypedWordValid)); + // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1 + // and there are multiple suggestions, such as the default punctuation list. + // TODO: Need to revisit this logic with bigram suggestions + final CharSequence styled = getStyledCandidateWord(suggestion, isAutoCorrect, + autoCorrectHighlight); + mTexts.add(styled); + } + } + + @Override + public String toString() { + return String.format( + "count=%d width=%d avail=%d fixcol=%s scaleX=%4.2f const=%d var=%d", + mCountInStrip, mMaxWidth, mAvailableWidthForWords, mCanUseFixedWidthColumns, + mScaleX, mConstantWidthForPaddings, mVariableWidthForWords); + } + } + /** * Construct a CandidateView for showing suggested words for completion. * @param context @@ -173,6 +289,17 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable( context, attrs, defStyle, R.style.CandidateViewStyle)); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle); + mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0); + mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0); + mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0); + mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0); + mColorDivider = a.getColor(R.styleable.CandidateView_colorDivider, 0); + mCandidateCountInStrip = a.getInt( + R.styleable.CandidateView_candidateCountInStrip, DEFAULT_CANDIDATE_COUNT_IN_STRIP); + a.recycle(); + Resources res = context.getResources(); LayoutInflater inflater = LayoutInflater.from(context); inflater.inflate(R.layout.candidates_strip, this); @@ -184,74 +311,52 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo mPreviewPopup.setContentView(mPreviewText); mPreviewPopup.setBackgroundDrawable(null); - mCandidatesStrip = findViewById(R.id.candidates_strip); + mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip); mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height); for (int i = 0; i < MAX_SUGGESTIONS; i++) { - final TextView word, info; - switch (i) { - case 0: - word = (TextView)findViewById(R.id.word_left); - info = (TextView)findViewById(R.id.info_left); - break; - case 1: - word = (TextView)findViewById(R.id.word_center); - info = (TextView)findViewById(R.id.info_center); - break; - case 2: - word = (TextView)findViewById(R.id.word_right); - info = (TextView)findViewById(R.id.info_right); - break; - default: - word = (TextView)inflater.inflate(R.layout.candidate_word, null); - info = (TextView)inflater.inflate(R.layout.candidate_info, null); - break; - } + final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null); word.setTag(i); word.setOnClickListener(this); if (i == 0) word.setOnLongClickListener(this); mWords.add(word); - mInfos.add(info); - if (i > 0) { - final View divider = inflater.inflate(R.layout.candidate_divider, null); - divider.measure(MATCH_PARENT, MATCH_PARENT); - mDividers.add(divider); - } + mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null)); + mDividers.add(getDivider(inflater)); } mTouchToSave = findViewById(R.id.touch_to_save); mWordToSave = (TextView)findViewById(R.id.word_to_save); mWordToSave.setOnClickListener(this); - final TypedArray a = context.obtainStyledAttributes( - attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle); - mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0); - mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0); - mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0); - mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0); mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); - mExpandCandidatesPane = (ImageView)findViewById(R.id.expand_candidates_pane); - mExpandCandidatesPane.setImageDrawable( - a.getDrawable(R.styleable.CandidateView_iconExpandPane)); + mCandidatesPaneControl = (ViewGroup)findViewById(R.id.candidates_pane_control); + mExpandCandidatesPane = (TextView)findViewById(R.id.expand_candidates_pane); mExpandCandidatesPane.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { expandCandidatesPane(); } }); - mCloseCandidatesPane = (ImageView)findViewById(R.id.close_candidates_pane); - mCloseCandidatesPane.setImageDrawable( - a.getDrawable(R.styleable.CandidateView_iconClosePane)); + mCloseCandidatesPane = (TextView)findViewById(R.id.close_candidates_pane); mCloseCandidatesPane.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { closeCandidatesPane(); } }); + mCandidatesPaneControl.measure(WRAP_CONTENT, WRAP_CONTENT); - a.recycle(); + mParams = new CandidateViewLayoutParams(res, mDividers.get(0), mCandidatesPaneControl, + mAutoCorrectHighlight); + } + + private View getDivider(LayoutInflater inflater) { + final TextView divider = (TextView)inflater.inflate(R.layout.candidate_divider, null); + divider.setTextColor(mColorDivider); + divider.measure(WRAP_CONTENT, WRAP_CONTENT); + return divider; } /** @@ -279,15 +384,14 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } } - private CharSequence getStyledCandidateWord(CharSequence word, TextView v, - boolean isAutoCorrect) { - v.setTypeface(Typeface.DEFAULT); + private static CharSequence getStyledCandidateWord(CharSequence word, boolean isAutoCorrect, + int autoCorrectHighlight) { if (!isAutoCorrect) return word; final Spannable spannedWord = new SpannableString(word); - if ((mAutoCorrectHighlight & AUTO_CORRECT_BOLD) != 0) - v.setTypeface(Typeface.DEFAULT_BOLD); - if ((mAutoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0) + if ((autoCorrectHighlight & AUTO_CORRECT_BOLD) != 0) + spannedWord.setSpan(BOLD_SPAN, 0, word.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + if ((autoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0) spannedWord.setSpan(UNDERLINE_SPAN, 0, word.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); return spannedWord; } @@ -313,91 +417,133 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo private void updateSuggestions() { final SuggestedWords suggestions = mSuggestions; final List<SuggestedWordInfo> suggestedWordInfoList = suggestions.mSuggestedWordInfoList; + final int paneWidth = getWidth(); + final CandidateViewLayoutParams params = mParams; clear(); - final int paneWidth = getWidth(); - final int dividerWidth = mDividers.get(0).getMeasuredWidth(); - final int dividerHeight = mDividers.get(0).getMeasuredHeight(); - int x = 0; - int y = 0; - int fromIndex = NUM_CANDIDATES_IN_STRIP; - final int count = Math.min(mWords.size(), suggestions.size()); closeCandidatesPane(); - mExpandCandidatesPane.setVisibility(count > NUM_CANDIDATES_IN_STRIP ? VISIBLE : GONE); + if (suggestions.size() == 0) + return; + + params.layoutStrip(suggestions, paneWidth, suggestions.isPunctuationSuggestions() + ? PUNCTUATIONS_IN_STRIP : mCandidateCountInStrip); + + final int count = Math.min(mWords.size(), suggestions.size()); + if (count <= params.mCountInStrip) { + mCandidatesPaneControl.setVisibility(GONE); + } else { + mCandidatesPaneControl.setVisibility(VISIBLE); + mExpandCandidatesPane.setVisibility(VISIBLE); + } + + final int countInStrip = params.mCountInStrip; + int fromIndex = countInStrip; + int x = 0, y = 0; for (int i = 0; i < count; i++) { - final CharSequence suggestion = suggestions.getWord(i); + final int pos; + if (i <= 1) { + final boolean willAutoCorrect = !suggestions.mTypedWordValid + && suggestions.mHasMinimalSuggestion; + pos = willAutoCorrect ? 1 - i : i; + } else { + pos = i; + } + final CharSequence suggestion = suggestions.getWord(pos); if (suggestion == null) continue; final SuggestedWordInfo suggestionInfo = (suggestedWordInfoList != null) - ? suggestedWordInfoList.get(i) : null; + ? suggestedWordInfoList.get(pos) : null; final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion - && ((i == 1 && !suggestions.mTypedWordValid) - || (i == 0 && suggestions.mTypedWordValid)); + && ((pos == 1 && !suggestions.mTypedWordValid) + || (pos == 0 && suggestions.mTypedWordValid)); // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1 // and there are multiple suggestions, such as the default punctuation list. // TODO: Need to revisit this logic with bigram suggestions - final boolean isSuggestedCandidate = (i != 0); + final boolean isSuggestedCandidate = (pos != 0); final boolean isPunctuationSuggestions = (suggestion.length() == 1 && count > 1); - final TextView word = mWords.get(i); + final TextView word = mWords.get(pos); + final TextPaint paint = word.getPaint(); // TODO: Reorder candidates in strip as appropriate. The center candidate should hold // the word when space is typed (valid typed word or auto corrected word). word.setTextColor(getCandidateTextColor(isAutoCorrect, isSuggestedCandidate || isPunctuationSuggestions, suggestionInfo)); - final CharSequence text = getStyledCandidateWord(suggestion, word, isAutoCorrect); - if (i < NUM_CANDIDATES_IN_STRIP) { - final View parent = (View)word.getParent(); - final int width = parent.getWidth() - word.getPaddingLeft() - - word.getPaddingRight(); - setTextWithAutoScaleAndEllipsis(text, width, word); - } else { - setTextWithAutoScaleAndEllipsis(text, paneWidth, word); - } + final CharSequence styled = params.mTexts.get(pos); final TextView info; if (DBG && suggestionInfo != null && !TextUtils.isEmpty(suggestionInfo.getDebugString())) { info = mInfos.get(i); info.setText(suggestionInfo.getDebugString()); - info.setVisibility(View.VISIBLE); } else { info = null; } - if (i < NUM_CANDIDATES_IN_STRIP) { + final CharSequence text; + final float scaleX; + if (i < countInStrip) { + if (i == 0 && params.mCountInStrip == 1) { + text = getEllipsizedText(styled, params.mMaxWidth, paint); + scaleX = paint.getTextScaleX(); + } else { + text = styled; + scaleX = params.mScaleX; + } + word.setText(text); + word.setTextScaleX(scaleX); + if (i != 0) { + // Add divider if this isn't the left most suggestion in candidate strip. + mCandidatesStrip.addView(mDividers.get(i)); + } + mCandidatesStrip.addView(word); + if (params.mCanUseFixedWidthColumns) { + setLayoutWeight(word, 1.0f); + } else { + final int width = getTextWidth(text, paint) + params.mPadding * 2; + setLayoutWeight(word, width); + } if (info != null) { - word.measure(MATCH_PARENT, MATCH_PARENT); - info.measure(MATCH_PARENT, MATCH_PARENT); + word.measure(WRAP_CONTENT, MATCH_PARENT); final int width = word.getMeasuredWidth(); + info.measure(WRAP_CONTENT, WRAP_CONTENT); final int infoWidth = info.getMeasuredWidth(); FrameLayoutCompatUtils.placeViewAt( info, width - infoWidth, 0, infoWidth, info.getMeasuredHeight()); } } else { - word.measure(MATCH_PARENT, MATCH_PARENT); - final int width = word.getMeasuredWidth(); - final int height = word.getMeasuredHeight(); - // TODO: Handle overflow case. - if (dividerWidth + x + width >= paneWidth) { + paint.setTextScaleX(1.0f); + final int textWidth = getTextWidth(styled, paint); + int available = paneWidth - x - params.mPadding * 2; + if (textWidth >= available) { + // Needs new row, centering previous row. centeringCandidates(fromIndex, i - 1, x, paneWidth); x = 0; y += mCandidateStripHeight; fromIndex = i; } if (x != 0) { - final View divider = mDividers.get(i - NUM_CANDIDATES_IN_STRIP); + // Add divider if this isn't the left most suggestion in current row. + final View divider = mDividers.get(i); mCandidatesPane.addView(divider); FrameLayoutCompatUtils.placeViewAt( - divider, x, y + (mCandidateStripHeight - dividerHeight) / 2, - dividerWidth, dividerHeight); - x += dividerWidth; + divider, x, y + (mCandidateStripHeight - params.mDividerHeight) / 2, + params.mDividerWidth, params.mDividerHeight); + x += params.mDividerWidth; } + available = paneWidth - x - params.mPadding * 2; + text = getEllipsizedText(styled, available, paint); + scaleX = paint.getTextScaleX(); + word.setText(text); + word.setTextScaleX(scaleX); mCandidatesPane.addView(word); + word.measure(WRAP_CONTENT, WRAP_CONTENT); + final int width = word.getMeasuredWidth(); + final int height = word.getMeasuredHeight(); FrameLayoutCompatUtils.placeViewAt( word, x, y + (mCandidateStripHeight - height) / 2, width, height); if (info != null) { mCandidatesPane.addView(info); - info.measure(MATCH_PARENT, MATCH_PARENT); + info.measure(WRAP_CONTENT, WRAP_CONTENT); final int infoWidth = info.getMeasuredWidth(); FrameLayoutCompatUtils.placeViewAt( info, x + width - infoWidth, y, infoWidth, info.getMeasuredHeight()); @@ -411,6 +557,16 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } } + private static void setLayoutWeight(View v, float weight) { + final ViewGroup.LayoutParams lp = v.getLayoutParams(); + if (lp instanceof LinearLayout.LayoutParams) { + final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; + llp.weight = weight; + llp.width = 0; + llp.height = MATCH_PARENT; + } + } + private void centeringCandidates(int from, int to, int width, int paneWidth) { final ViewGroup pane = mCandidatesPane; final int fromIndex = pane.indexOfChild(mWords.get(from)); @@ -436,38 +592,29 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo } } - private static void setTextWithAutoScaleAndEllipsis(CharSequence text, int w, TextView v) { - // To prevent partially rendered character at the end of text, subtract few extra pixels - // from the width. - final int width = w - 4; - - final TextPaint paint = v.getPaint(); - final int textWidth = getTextWidth(text, paint, 1.0f); - if (textWidth < width || textWidth == 0 || width <= 0) { - v.setTextScaleX(1.0f); - v.setText(text); - return; - } - - final float scaleX = Math.min((float)width / textWidth, 1.0f); + private static CharSequence getEllipsizedText(CharSequence text, int maxWidth, + TextPaint paint) { + paint.setTextScaleX(1.0f); + final int width = getTextWidth(text, paint); + final float scaleX = Math.min(maxWidth / (float)width, 1.0f); if (scaleX >= MIN_TEXT_XSCALE) { - v.setTextScaleX(scaleX); - v.setText(text); - return; + paint.setTextScaleX(scaleX); + return text; } - final int truncatedWidth = width - getTextWidth(ELLIPSIS, paint, MIN_TEXT_XSCALE); - final CharSequence ellipsized = getTextEllipsizedAtStart(text, paint, truncatedWidth); - v.setTextScaleX(MIN_TEXT_XSCALE); - v.setText(ELLIPSIS); - v.append(ellipsized); + // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get + // squeezed and ellipsezed text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). + final CharSequence ellipsized = TextUtils.ellipsize( + text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); + paint.setTextScaleX(MIN_TEXT_XSCALE); + return ellipsized; } - private static int getTextWidth(CharSequence text, TextPaint paint, float scaleX) { + private static int getTextWidth(CharSequence text, TextPaint paint) { if (TextUtils.isEmpty(text)) return 0; + paint.setTypeface(getTextTypeface(text)); final int len = text.length(); final float[] widths = new float[len]; - paint.setTextScaleX(scaleX); final int count = paint.getTextWidths(text, 0, len, widths); float width = 0; for (int i = 0; i < count; i++) { @@ -476,33 +623,35 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo return (int)Math.round(width + 0.5); } - private static CharSequence getTextEllipsizedAtStart(CharSequence text, TextPaint paint, - int maxWidth) { - final int len = text.length(); - final float[] widths = new float[len]; - final int count = paint.getTextWidths(text, 0, len, widths); - float width = 0; - for (int i = count - 1; i >= 0; i--) { - width += widths[i]; - if (width > maxWidth) - return text.subSequence(i + 1, len); + private static Typeface getTextTypeface(CharSequence text) { + if (!(text instanceof SpannableString)) + return Typeface.DEFAULT; + + final SpannableString ss = (SpannableString)text; + final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); + if (styles.length == 0) + return Typeface.DEFAULT; + + switch (styles[0].getStyle()) { + case Typeface.BOLD: return Typeface.DEFAULT_BOLD; + // TODO: BOLD_ITALIC, ITALIC case? + default: return Typeface.DEFAULT; } - return text; } private void expandCandidatesPane() { - mExpandCandidatesPane.setVisibility(View.GONE); - mCloseCandidatesPane.setVisibility(View.VISIBLE); + mExpandCandidatesPane.setVisibility(GONE); + mCloseCandidatesPane.setVisibility(VISIBLE); mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight()); - mCandidatesPaneContainer.setVisibility(View.VISIBLE); - mKeyboardView.setVisibility(View.GONE); + mCandidatesPaneContainer.setVisibility(VISIBLE); + mKeyboardView.setVisibility(GONE); } private void closeCandidatesPane() { - mExpandCandidatesPane.setVisibility(View.VISIBLE); - mCloseCandidatesPane.setVisibility(View.GONE); - mCandidatesPaneContainer.setVisibility(View.GONE); - mKeyboardView.setVisibility(View.VISIBLE); + mExpandCandidatesPane.setVisibility(VISIBLE); + mCloseCandidatesPane.setVisibility(GONE); + mCandidatesPaneContainer.setVisibility(GONE); + mKeyboardView.setVisibility(VISIBLE); } public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { @@ -526,8 +675,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo public void showAddToDictionaryHint(CharSequence word) { mWordToSave.setText(word); mShowingAddToDictionary = true; - mCandidatesStrip.setVisibility(View.GONE); - mTouchToSave.setVisibility(View.VISIBLE); + mCandidatesStrip.setVisibility(GONE); + mTouchToSave.setVisibility(VISIBLE); } public boolean dismissAddToDictionaryHint() { @@ -543,12 +692,9 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo public void clear() { mShowingAddToDictionary = false; mShowingAutoCorrectionInverted = false; - for (int i = 0; i < NUM_CANDIDATES_IN_STRIP; i++) { - mWords.get(i).setText(null); - mInfos.get(i).setVisibility(View.GONE); - } - mTouchToSave.setVisibility(View.GONE); - mCandidatesStrip.setVisibility(View.VISIBLE); + mTouchToSave.setVisibility(GONE); + mCandidatesStrip.setVisibility(VISIBLE); + mCandidatesStrip.removeAllViews(); mCandidatesPane.removeAllViews(); } diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index baad66d875..97ff3e4adb 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -288,7 +288,7 @@ public class Settings extends PreferenceActivity builder.addWord(puncs.subSequence(i, i + 1)); } } - return builder.build(); + return builder.setIsPunctuationSuggestions().build(); } } diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index a8cdfc02e5..84db175047 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -24,15 +24,17 @@ import java.util.HashSet; import java.util.List; public class SuggestedWords { - public static final SuggestedWords EMPTY = new SuggestedWords(null, false, false, null); + public static final SuggestedWords EMPTY = new SuggestedWords(null, false, false, false, null); public final List<CharSequence> mWords; public final boolean mTypedWordValid; public final boolean mHasMinimalSuggestion; + public final boolean mIsPunctuationSuggestions; public final List<SuggestedWordInfo> mSuggestedWordInfoList; private SuggestedWords(List<CharSequence> words, boolean typedWordValid, - boolean hasMinimalSuggestion, List<SuggestedWordInfo> suggestedWordInfoList) { + boolean hasMinimalSuggestion, boolean isPunctuationSuggestions, + List<SuggestedWordInfo> suggestedWordInfoList) { if (words != null) { mWords = words; } else { @@ -40,6 +42,7 @@ public class SuggestedWords { } mTypedWordValid = typedWordValid; mHasMinimalSuggestion = hasMinimalSuggestion; + mIsPunctuationSuggestions = isPunctuationSuggestions; mSuggestedWordInfoList = suggestedWordInfoList; } @@ -59,10 +62,15 @@ public class SuggestedWords { return mHasMinimalSuggestion && ((size() > 1 && !mTypedWordValid) || mTypedWordValid); } + public boolean isPunctuationSuggestions() { + return mIsPunctuationSuggestions; + } + public static class Builder { private List<CharSequence> mWords = new ArrayList<CharSequence>(); private boolean mTypedWordValid; private boolean mHasMinimalSuggestion; + private boolean mIsPunctuationSuggestions; private List<SuggestedWordInfo> mSuggestedWordInfoList = new ArrayList<SuggestedWordInfo>(); @@ -118,6 +126,11 @@ public class SuggestedWords { return this; } + public Builder setIsPunctuationSuggestions() { + mIsPunctuationSuggestions = true; + return this; + } + // Should get rid of the first one (what the user typed previously) from suggestions // and replace it with what the user currently typed. public Builder addTypedWordAndPreviousSuggestions(CharSequence typedWord, @@ -143,7 +156,7 @@ public class SuggestedWords { public SuggestedWords build() { return new SuggestedWords(mWords, mTypedWordValid, mHasMinimalSuggestion, - mSuggestedWordInfoList); + mIsPunctuationSuggestions, mSuggestedWordInfoList); } public int size() { -- GitLab