From 7c89ec051a3ac605b2a64a0c1431801c7badbfcd Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Sun, 13 Dec 2020 08:14:32 -0800 Subject: [PATCH] feat(adb): expose a11y tree (#4694) --- bin/android-driver.apk | Bin 582144 -> 580631 bytes src/client/android.ts | 6 ++ src/dispatchers/androidDispatcher.ts | 4 + src/protocol/channels.ts | 7 ++ src/protocol/protocol.yml | 7 ++ src/protocol/validator.ts | 2 + .../androiddriver/InstrumentedTest.java | 78 ++++++++++++++++-- 7 files changed, 96 insertions(+), 8 deletions(-) diff --git a/bin/android-driver.apk b/bin/android-driver.apk index bb51655417a6a662d59c36c46212c040cb1b413e..66cc5a2c0af6f249adfb7ed3e233756b34f5e246 100644 GIT binary patch delta 11651 zcmY*&?Q{lU4q>pf#3vp3$DT4-QDHE-Q5WeK@;5F9fG?v-W|i&PQ@>g&<2pn?9py0lCP>Y?3+p6AT^c4eU05}ek8 ze7?MM6JiPSechLlJoRW&<1O>1(`u9 zA!+$-Y@@M3LB9{wH(3~1sDFkCMUF@gBGWz?z)2RyqyXZIgt5ae8SnUhZ~W<7HvB5< z(nDBp!V>+{!Afe;bj$0>>Fze>hnk7^VGe~L#qP8ag<8TewCySwy(+t91nAniJiXjP z*Na&Nho2l}e+c&q*yRtogE-itiJ-h1Ajn-TiJx^}as0*drQ8Jk9$vHISs!lBAr()2 zFV7hTm%x@>;Nwqn51}}x2eCI_n+{gPqDh!Z_qOwv`cYV#fnA>O9A&Dw^CXKC`YA7s zMlXBM%|N)iSlYbYh2-3U)AMHB`BKm4Sjew|&g^S{c0|nXeFp*J`KK=kbGn6?+BFe*BzE3&$b_i zBxYn4#jD*AJAoYkSD)m-rV*)>JW*$>cI-LiD|XD*`AfR-N(2vUQzls+%&Xt3z5-l+HjE9$t9l z6dNcYq_Nq{?VC^@|Inz_Ni#rPxFpL^J>o(r_-U^DM{YBQmFHO~Prw5%A)CP%f~23P zI+910s_0sSXa$qj)s@z~fi(o$o3V2vBsj5eZ(vE0rw~#``P)P4P7gXK=;QiSWeC8~ z#<+_L+A(i={^6slME~!<9%>l#Sn$C2ujeT2#%e$Q%5>T>+iwjGFJKXNIG{~5GQ(!y znnxk&h7V$Pf0pZH$~$RHMlB=wI4u34_q(hzE8H0IZ?ytV5l;>DoW%)HGM;P9kB~@R z52aKBLgzgcSQ2bXH;&CyoS>{Y*VJjuGda9#@$S^btl=xUlo}sCgZVQOr0p3T&68fL7{4QOVn>p9`9b+mr%DxFRFx}*Q}ecS z&vUGKvu?|id$#ybdz3u)+7!`1LPyT`x(g*K9;X&=4APnKTh5liah<7Z;>WeZYy*=J zO;z^Vi`tLKsUJty>quXH>}*-|C%>aT_i9R6jm7T_Clvc9X;CmhdzPu>-mtb0P|J6cZEHtx zp+A3UTt_J&E7PFfk08}?jcWQSd)**)9kqV?hv<-T$m9Ec0pRJTRxy#rAAI#xb|-ae zIjFnd@ifyMr;*t-yQmoa&CD1hcChj(^0T?t64UY}+_-2r>j*-+`f7*6HwMW#Sf@HA z56H$?E~aAsFpf^dJN=awpi1vulih_Bq)~VkmQ6woP3g*#{_{<+CfX$6YAQ3V!p;@D zujxp{ebKkU@+trNh5pwP7j%q~Ls0w9g!!c0Qb0wA=1=c_Cb8Nv&if%_D>?0k^0IN5 z7-E6n9JRx2e1tS(VB038Ka<|~)6aQ%!~E*H(jPWt`WW38qff95f%_yepq}C{iCL}D zd_SgLoWr69wJbU9ilJmZ{^L#1@I^e@uc{ zyG*|^En}$oC4v>~JwBM$ftt?06fKu!-if`R=v*6Q(qiuP3 zOmBHh@l8Xwx0&e>=S-4~Xt_&uo~7%kFROL}MD%;V*Wo@#<*%vqmmXVRKAOV1?fJc4 z)+zh^gyv``qeIGPixKEGxG;%D1l)8&rDrmX)dxA29NyJZ08j!6=m5RBHyiN)JqR2I zh7JRR!oVuDolhbF(fmDDkS|HQR?Hh)JFb$W`q)hFQr z4ZF(fra?hpRUMntqUJmGnuSFTpGIRFpXzhFi{|?kHj>ZE&+U+SzL&1YMSY+1&L#iq z&gl=>Y+>s=CzH49W#N{aR11M zEt1{nWIDinM5F;W#~ItJXBr=80|7l9v$fY}Jd#W>_jnLX44fyip8?`C5OlWMF~SMLmP6ffa<)MLB~fgUW;6go?6`2oeUk>OMR${KeZg+pZPX zWBh}F-DB57zRj{75U�*u%MvzD+BfFXIZI@GqAHiVW_JlpBP*gp~`LfJy^lZ6j}g zbVT%oar}*=20b50W=LFz@xb&~b{la!Pl6pQ1HB5WEl|Ek-4LM;qvb;j9yioF+Byb5 z6hABphzu?d)*nFSN9lli0db>tz<0oPz`S5RKs^w%P>1-#+ys2;kuhX+B(K970j&kl z2iOD<2Mz~X1mr_AL)U^FK$jpes6T*BP8C@dq}C($9Ul>fu?O^>R1+x&VITml2Yq|K zhp}g)C%DI?hpk7p2MlEa^9L?S7{w8O2090UD&V}w4fwa**PiBp;Q#}W1I#5f0Jk11 zRuph0%)x?G4wn_^C5%vq-+~zd9o#e6qt;`;t-h_ljkRsHP0%ymlikDDlMj`pzz!;h z{Sip?5j6*i0W<}#4myH54TRpt-lj8Tc7$pHKXCqq`Ikbv?I&zQL4+g+s{msTg%V)a zL$?ipz9UFM5kRLyYry2g+e6vIT|jrC`x1DPdE$8zJn(({EvE{v3fc>l?l}=A%s`re zn*#9$DE!+NK}@(^VdUk1$I67@4q}E8CrmT`j#~~Z0b>$CXUMRPFa*69s1krA%z+6- z4H7ZLcBEtZAgoDl>(_TrZEM!o^vPDfZxNuhW$a_6VUX^dBbVc=up)O&+(vJNVhd1* z+KI)yx8!6&$Ut$-;ls&5m_WdXLJ8zF#Hu6YM$rT{z|aTW1boJXLH$m!ElBA)rWl!& zFN$z|U7sK@bDDbH1VXwDKIYi9YXhtFb3q^ z@dxOpncW9wDplR`OIBGB=h4@Mo8__9{@Q6Z5qO?(#=AYEnI-@<554v<#`!&7j6MwR zmw~qU0qB$iZ_OH|yWb**7|r9X@xPPq&&0{nRlKy8SiLp}brR7p4HHS$PD(?dPBVJrAaO-4cFLY4J- zzGR>LScBe+Z=XYE6V9tTskZTC<=wty3+0jI(-!Da_f!4*qxVJQD8{Pk#S*WXf$cmv zD5v(wX{2MwtNZVfZ-CkTJLq3f{-2+qY(nS%-5LDnXhL`*EXEMvwHSK*MZ$; zSl&?(h-@FY=BE6spxbKj02*$eM;6Q2oF z?Yy3fh5RIhz-A74f!vMEwJ!U*1s$>6XOE~f=JXxEP)si*MIRH5MhqrN&NoJNe_l~E zNa7E_(0IWcG*Elt7{mZR`+vJy!UMiueci@BsMT?*Fpl449n>Ghix6&Cnkt*4{Heo9 zF`1KaMy^t#k|g`N@|LG$tMmbRP(#Lj-Y!Y@#JvO%`xTz2=Bs%E6g{|=02ur-kG&KA zF`~DILfn)8M#UA3#d>g+g;2%{hWWh-u6^m*@aG)iGlbI>41j6apXL96|DsGBDX2c> zOA|=n&z2<7AA66woWPAnpG54_Jz?sGA`Tw>sLN~7#Zylkyg6pg)GuFFY&Tt1%vbZR z-t~*}%2hS`v`Mj|O{2#Bv#W5fLxFqpG$eBgiLDmLT%Ts5Lm}h8kS+}AJQ<-x-7-(Q zS3tFdF;B5O?F24L=S0ZNyY0*YPeJ_xqA4axM$oM-=`SX8A;bpB_6j$?=mzuc-z3q@ zii{@Xan0+EUDyvoK6hz+d7eD?mApoLDlkQOm2&ZOuzo!Yj~>PPjn_5E+Bnlx$y_r0-hjy?3}!Sh}%L_ewu(vr*=a>jx(lo{^&RA z*1R`jex&AzvYuq8wN`XrqBDQ^8nwGc<3T_8lM1>nxlqYVO1*F$=Bwz`QrIW zat&bJ+Oehne*es-u}~H^2sx>!?=xu&7Fk*EeCn%f&MMa!`$cY2<;l@D^@4vr@XLm& zm|#|I#377}OA394Y_x3DJL`)w*Z3_(o7y$5mI0f+t*!%`xAo5h10+{GVaA?(Bj1d7 z8+brxI+bROz_)H!1v%$)x9Wk9AVs(G!Oe)Bi$AR>v3MK3;f9M@c7nB z4i?$eO%=Lmx%NfapB5Ma;0ZB+N3l17A7d!Lr|xdT$4fgpyvIuJ-;*~(=hee4+JhE5 z=TJ#{{D!}Z?0oFL_h5y2{&};WWdKfd#%aA%CG?Q#6vZv#;&r4P<1C1~TBh`O!g*|v zPCiWd&=uCv7Ve8@ZU`=%DVBCAXpdBGljQ2m7nhFjzkC77^G^QKJHO@zmYs3svn;hZ zk>blG=Yd>%Zo7fB$GjyR68xY~Y0b`~mKH9{FA)Z=kEuP^iQZ$ezqQx(Udd zp0q7EbTKc`l`mL7Z*ndpGf)7Z{8hN(>!!C;Pg+~}<1DfnUxw8Te61P$%V6#3nWGsU zsLj9Tog-fPvP#*+8xMY7fdeZrKR7O%zbn}|*%y#(HCA)H6YI3@t??8Y8W_|8uT=LI z_-AFbKJ@CA5m?#OSa#6QR)`$yqduw`o5Xe58>>>UHwRtRTc%sbLqjaFa}InQVzIF} zjc@&Tmg9`tg9c%KXdKYp_l(&W8%A3LS+o9jmGY3M zy4u2_y(PiA6MdrlNTNxIer0*l&Z6N}r5Bc|Y!j|}Tm1AGfbPzr81s9fu3kLZ) zJ|EqLmqnuBZ19>4-js))cOY?i6Y8BoG?^k6iH8?Iq>xDv<@FZ9(;1VO3@y&~S!<|% zMGE;yqK7zc!E+1tdAvs?=YjUJngNN1O0arD_)B5!38Psp<`tGjpNEPjTc?>!@InbY zS&4{TVwMPS`Kdfmb`XX0V4c_!6X=JGcuRanqo|tmOojgto zM0myvavADAM5b^=?90@PT2=it$xf9qi6ymBr;Pp!Of&Qu9A9w|^YuHd8A9T*T~xu{SoS95Fkp z`xxE``^%a7T=6X#kqcwbmb{BA1a&ems{tgn0e=f5tctj}yuTcNYO(RW6}cP)G%H&^ z!FGj|)e~^Y|L*8_8N9@Gt-Db@_1l}}SYHXq9c@nitA~r3i^i+mQah4zvY<2;>(gU^ zLezCrcZgn6(bJ*>X`C(3zU&I#gsrvsJ1FI~|7M2bnm*JY261{*NH_QjeLO6DSr$E; z9!!{CwXDxfb*b``5q^X z`?I)Xdm4Lr@dXF4?TQd_KtK1KsYf3u4`P3~t5&d{=vE zAMz9_8=Y^p`^g5|d6(5?4cukcuuq=BCH(kZ9>!37q(Qv&y+vNJozed1!>^lqs;*Xx zjZk-v-EJJ{`C@*)N052064GHAwmQTcow!F0598&(dvW>tUpGlTStWG;UaNHL$oDe|msgWtPY~LT+Yg@Do%%co=@}kq%FIhaMVN^e`p^#DlNp1-AItW?GDtk>#J<^O z%5z;{xIIShNJefuEiY?GQQn!J?V2;B-8I?fY?HiiPFW|r3fa2xE4~=G=^9qKh3P($ zE=Jd^pm7Rk&O7OQeATU6j;b1T#=z&}2~x*TRv40sJe+Onv;L_8Z!h@^SN5AYK0b>#@L$ zMS+mGpL7{OhEf_l&Rk5Y+w5ntd^4WZ)y8zLnc>Vo!Fzu-Ndt0bX@o!g!Xk zp1N&+x1HAub(i=ipSb@rD|qCO8Tsshg&1S_srMq3kEGTqN*oEuL@ zTWML!-Oo#$8$`b~LiLxpc*i6=!h&7ensASo$+>GP!B6Tk+OL^thwD!I{5YU|4V-i<%-}6f;Gu;(rbL80km=#$0 zcXRsoqK~MiWbNHvfH6zozj@pzik(^DX6RIi-%anzA?wdq*Oh$H+XGD)zc2Hmt*7QQ zH8dBFc?S1YY)+ObHj9}{E&Bd#)(i3;LfwB>#ruIuYHl)C!7pCtpAeMLF5fnK7NEK> zM?u5^DA0m#d;wliLKrS*`w&=PAr}yp<}d#uYnW-6L#UUrfO9O8zht9y;nj@e>VcBb zx=CA^+_;Lus2T8H$Pyvb`^v?Se$AMkiZOmJ$is-$Cqx2{9LFTSrz$|%+~bY;ylG`; zaz4N{z1{JF+ypb9o@C+gg}Sb`QJ7FK4f^2>uahlLAj*DbvV+CZ`>$LSpQnF!RK*8~C_htVrCgru4Cq^@~fBmnXiI9J0!fV#j*Vv$?a{dZMQ>?h2LfuW$ z)(xMx_*ITKtM)G|Or-?%vbUrS;~scIuLQsa?aSh9Y~yj-sQ{qih0A$n@>Y|y^wllK zzj-DPTZrIb+|^s8VWvNekPi4(=10+C8(h=ABWZJprG?$ns3AytQyW;oibyJwW6Ufm6fKABhMBf9;4vQHM6Pxp}bgaqXd%I5@_Rf~Z*CyIy@6swU@%p(8w#;eOAG;Tz{WRW3%+<#-DT^(e zmWs|jJ(iK@XBwN`Y8M;l)w6Y+Trqi{!KyrF%FV+xF@j>teE02*%1cl)G~IFa1=&uN zx``gI=88rGb~P&f50UAn#Np!OGr&xqz%3MpkUxZ}j9F))`^WsJRR! zMHBAyeDgWa-N<7hb$iH)mk4+GahIrby5o@BRhJ|37UHT!1!U$t^u-~HdcT|La9?kL z`(3ypB9W}jzf@)IYrK{`+N?{9vOs~&SGBKgZ+uFy?OV~iW(s;9>&!u-E&y-ZNnG^; zgD!`N2N~`v?8aSrdF^6!-tG#$zog}z_vp}yOPDL9R{WK>^Y)o=uYhsN*dlWNoPpFp z&!AI**+JlcXA!`AErqHlD1P0Vj;_lD!1` z^rf1)Kd0fL=hS0S!mcZ255LM6Ar!|q!rwjoL|YS$nphKV+#Jh!TY79oUy~kdEDv-p z;r|#Kl~|1VnvS#U)C+=97*?VX7;aqf*=pvvFei~T4+RLY= z|Ht@`WPov}g9UFol6u#i-v_?+P*YbBI2en&553W7uGQ@7>Wp1SS#0oVs5bDs7!%*u zONgd1MoBhz=x|sK8!1KPS;J@4biwCYRnMu<88F5^FK+bsX4alLTIvE5mdRmU87sH= z3tv{+HKE94c6XupU;m|{DEJl~@j-jcfVCC<$<0+pav-K8`AYM1l1ymaBEjfT@}cby zI#WmqWyPB(JC1f{O!mqO`ytqcH}*5@50nq3iD+(AMTuhRiJPXy?Mbt-@Tfz1J;G)j z_`f&@Vz@|#dM zQBIMAKIfq}ivLPYC>E&eM3RGNAj@Y-))q<5-k4P*;d$X=pZk+$);Z(wedcf2@Xl zAEWH%O}b$F)wH^>KALrXs18BCu{NG6BHTg^VgusYGKykJe0}sa@NIaK;%KvrY^cKp zFlC7ShQ3*vQAK|b86{pwl!JtFnkJcBS}jE#+{~Xu#83}g+WD)K+2n&wYfI8ZlH=Lj zwbjWv9t~62rXww$Et2c&U#mV4SI5H$mn89RIMj)CSKm{@-{QFxraL|von&0i- zRRiqiv6&)&mv~S_PvLfDS&xu?*`HV$9~@t_afr+BK?PNnsd}TFuvjRx_@u? zh9&hAL7a7eOkyQXCY#9z$C~CPDHZ94tq8zA=9UVTE~yZ!XxCEc0-L*NM7_(8T2d3(;Q+_+mMCk6{U5^TpsmK7{lL?6MVk%W1vvScgg?HSpGb}sv&DsteX z1v9uqu2oJb^_IG*HD3**KfM*Z=oq(FRPO^ zma9F8c=gsOZL}q!{En*dxheR@RrTud!ym65;bq4uVZv-NX_WCj0y$&Ec$p}RY>Ov* zddgxm8ZjzJ4s5T|WXyPjH}E+|%CLdOT!kkEri$?~c$93}r$Jf{7D_`?j9)p#g7 zLpxwP8wCIl2;zl&~zR|Kjof;h*HZK+J{oo1+}aaj*a=d?^!RB z@s(0AU$^hIRD6noTg>|XOi3u=TVWJ3026FRykjJWO~bA2dPnT*m=uwWKYR-eI+am+ zF$VQ|wB>;F*@Q$Kl_!e;4~y$E0bXc{RhVEQ|g$ z7^()_Dc9pK#y_9P{v4NfHNd7xO(@m6xh^#d1*2lYZ-Z)DZdnxAE0IouR7BAJ(I~@j z`NOA3Uk+7uOf%BBKq-=F`;V-^Z)(W5St#D2@!uRD6{+ZmBeGjA-S#%a4HeN<&^47e zRi%nYGNXzqVfK?k@Q|hqUk(Cg4p`M%loNGI4-Rt2igUVCDuPHPu*515ErF(R zxpmXhtI*CxS<^?7RP^ViK3W>58*`4@{me<+jhP+BP$?hb6=Z3b5#|0dLU`gyg|%gk zdoQacvM~DQnZUq*jLBLLJX+wRk4lXR?2mj$Zm1oiO=k7PGW#WgoXAY6(Lgz#T^(_W z&i_f9Q+jZvcs0hGGm`?r-bT~f^QpgW+KACMis~cp10vPYp(m>Bbfm1+;&)?derw~1 z0etOxI~|=bMvqq>noqvnhAKqa1JwXWo{KW z_N7RE=YyQUU~kJ(1jilc9cTW)gBXVG=ap67qB8PDTtN}(wSHo*S+@F;lI9~=c@n>U zLB7(xua^-hi_^-1V|z# zOdA)TSlw30KZ0DvWK77;7B zNVjZ(+__L71(6A-AwE7*EnAXLY4|&WptC&a2J4Gv>qLa?;o!bkmb1-#n)UD_%1$Ut z%nKi4rD4&X%~0>HyevG7rfbErK@+&QbIkT8J~CSz%cnt3_j^`oAg;m61b*0*TmBaO zu#@tL#?t)`JTg8Y{>^%NPkd>I2c81+MF=z|x=S3ri*}(0OO4;U$8++P`O7l^4r76= z^c*;_1aH|~Hm-v@f3auuZgmv1@IIVdLS~250~C#3?mae>yz$BVTeyRJfXdNsmm58Yxfe(lh2g6o`uk)ldL|&b`(89E zL@pmT0R$I_OxulipM*@@UAN$v)`Y*;*5I%{54>BbNow5(zk1LLyyt7YIYruag%c#a z!~Fm9AsXc}-(*2}5+F8RI=OHPe-J`CyHx;@z$-!~y~2+`j6w}!Jy({3moGKNe7TMP z^NzWor1*4B*BAA?x6bc%APErS`8kB& z+w5>Vlt?-QwRL;j<3(elcfOxJMduUXpKY1$ekDP5tTFY+)CBF#PoiDxI10i;*VqI zASs_pN}A_8K@&&=1+v75lj-M+w#8rVb{P0{zP~5D@%|-XP%jd0#lRm?vcwHj(P0Ry z$f!?kmc9EvJS#tYZf0<6b05!uqQJyV62SWqR7wOLjpCps-HD#X2);Cx;lxJxqtIN< zfX52_AsQN4yA%T7rIXnkq5Lv#<6~x7JKL_x4D2?!_-krY#P!Y5Uy$E;WImMixAkH? z!|s#(RR&H;Ag7#>Nl;U0i)Sw@Go?lOYE&&m{$96IfiJ9p#Cz2dQw94O6yceU7C-)p zYj|$FFksX)@lEYADnxRf&g$GP->0}MTG|U>J45-sA!}4XY2u?gZys68S>?}bve^!9965KY{mc27p@BYBT)l#UTOjgDwG78g>bos1m; zg2U-K&kQ`rP$O5S&NQW!$^J_DJOh`NQKm<2#~exTESqAazqonHY(&ug@q5|q4nvGF zBH^n9$8IfWsj|ft0%Zsqua;QFN9~I@-o%xxASA8PPao@XcFkWMcAb-!;^;^W0^m<} zPf)T=*IwbtxFYHLc{$=I3(bQOGL1I?p)fJBxL*5vcukhXFakt$3Z5miND#uhHVM2y zXC!58i6s&#vRXn3cbph?-L-j5Z2d{f5p5>kTJ`v`RsLq-SO?mPz!s^z@exU1<l)Br4h5?q+CZO$4Z^7d|qP+bpKOaK)_%8Q=QODi~aio z$NdL-Y1Vf#v)m%HqRsOo?R#cmNZ#lw8bUYIx*Ed{Q3^CXFBzr+uYO8oawt2{)|L9Q z#NkuS-O|$QxM%|w?zBBB{J;t@^arw=cL}~ zA+lxqrY1LXE34wPeM#AVlxL|dpEMOa6h*Z}TPg1uA9_(^kcqm`+r9fiEGNrbq0Ei* zm&nT)dznQe4zBaoFa@(x6u3^Zb*SMpEMKj|m)h7UkFR^XDHCyNiob;@;JQH(tK~Wn zhRo0IbRo{I>crkYg4|C)Zy6U~qKuchvf$A??Ey478u_2BrM(s7$GUHAGG7>ScXN*0 z__-Rk9`g!UAY$>#aD>$OqU_yLuah#p>|^@<$ivzD1HtlOREZ$hL7|xwRuUo^a{e|= zc4LSf*%PQ?4jh_0jGV_C@Qd4rhc!`dM}9|R`1gq3%ZQ>?B2_TZMMxEePi$0G(f@;S z?6X*X^KN>}mgmi065Hf!?_w5?Uj-eg7%9o5RLYq*a*YZN8J)W%gg|DL9_>Q52 zVE#YZQH@56(0$P2SlmHYwiVe|QPqj73&LMcn{#h(qHeCA2ZmSF-swG7W9tzc4k{N+ z#c8XFXP-Oe1+{=uk_`p&^fUj~dH1y`Sb4}uFFT$QGd%!xs=8S{5oOV-lcG;&E#L3 zNHC}_H{6W?Nk^Eab7?IE{?(bN?vLwRS&&xGWS9_r99Fd+$99M0Vgcr#PZr4y(0 z_TUCMo0i5UI*;~8N4vHi8i>hq3MqOS4P}q~!(BV{>9Lw0ZD@EV7zLDBYGj2zD3$VR z+qS$uQx?TFcG~(vpZ|uE{%a7C<)aPirW+-;uK=D*;pt|u)32G{h^?2mUcJ@qEUem- zs;Xwt5F#`P2r40KsPq6E^e>vsK)55)hQ(!C&`-_5BZ&Tlr2jn$BoUyXmN1~8 zF#i)8|6fyWK};vxK_n;nfAT0ODAfN8|2Ij^PS@E%Bt!d8IIRbQf`WsAg2GBi-$4YY jm+T}* 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 { + return await this._wrapApiCall('androidDevice.tree', async () => { + return (await this._channel.tree()).tree; + }); + } + async close() { return this._wrapApiCall('androidDevice.close', async () => { await this._channel.close(); diff --git a/src/dispatchers/androidDispatcher.ts b/src/dispatchers/androidDispatcher.ts index ecb1083f2d..a952a8d32e 100644 --- a/src/dispatchers/androidDispatcher.ts +++ b/src/dispatchers/androidDispatcher.ts @@ -102,6 +102,10 @@ export class AndroidDeviceDispatcher extends Dispatcher { + return { tree: await this._object.send('tree', params) }; + } + async inputType(params: channels.AndroidDeviceInputTypeParams) { const text = params.text; const keyCodes: number[] = []; diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts index 9c3b040019..dd60c8adbd 100644 --- a/src/protocol/channels.ts +++ b/src/protocol/channels.ts @@ -2461,6 +2461,7 @@ export interface AndroidDeviceChannel extends Channel { scroll(params: AndroidDeviceScrollParams, metadata?: Metadata): Promise; swipe(params: AndroidDeviceSwipeParams, metadata?: Metadata): Promise; info(params: AndroidDeviceInfoParams, metadata?: Metadata): Promise; + tree(params?: AndroidDeviceTreeParams, metadata?: Metadata): Promise; inputType(params: AndroidDeviceInputTypeParams, metadata?: Metadata): Promise; inputPress(params: AndroidDeviceInputPressParams, metadata?: Metadata): Promise; inputTap(params: AndroidDeviceInputTapParams, metadata?: Metadata): Promise; @@ -2594,6 +2595,11 @@ export type AndroidDeviceInfoOptions = { export type AndroidDeviceInfoResult = { info: AndroidElementInfo, }; +export type AndroidDeviceTreeParams = {}; +export type AndroidDeviceTreeOptions = {}; +export type AndroidDeviceTreeResult = { + tree: AndroidElementInfo, +}; export type AndroidDeviceInputTypeParams = { text: string, }; @@ -2802,6 +2808,7 @@ export type AndroidSelector = { }; export type AndroidElementInfo = { + children?: AndroidElementInfo[], clazz: string, desc: string, res: string, diff --git a/src/protocol/protocol.yml b/src/protocol/protocol.yml index c243c87b0d..ad82b20c6d 100644 --- a/src/protocol/protocol.yml +++ b/src/protocol/protocol.yml @@ -2200,6 +2200,10 @@ AndroidDevice: returns: info: AndroidElementInfo + tree: + returns: + tree: AndroidElementInfo + inputType: parameters: text: string @@ -2369,6 +2373,9 @@ AndroidSelector: AndroidElementInfo: type: object properties: + children: + type: array? + items: AndroidElementInfo clazz: string desc: string res: string diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts index 013598a0a8..16c8363dc5 100644 --- a/src/protocol/validator.ts +++ b/src/protocol/validator.ts @@ -965,6 +965,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { scheme.AndroidDeviceInfoParams = tObject({ selector: tType('AndroidSelector'), }); + scheme.AndroidDeviceTreeParams = tOptional(tObject({})); scheme.AndroidDeviceInputTypeParams = tObject({ text: tString, }); @@ -1074,6 +1075,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { text: tOptional(tString), }); scheme.AndroidElementInfo = tObject({ + children: tOptional(tArray(tType('AndroidElementInfo'))), clazz: tString, desc: tString, res: tString, diff --git a/src/server/android/driver/app/src/androidTest/java/com/microsoft/playwright/androiddriver/InstrumentedTest.java b/src/server/android/driver/app/src/androidTest/java/com/microsoft/playwright/androiddriver/InstrumentedTest.java index 4c9cb6d7af..f8e930e61c 100644 --- a/src/server/android/driver/app/src/androidTest/java/com/microsoft/playwright/androiddriver/InstrumentedTest.java +++ b/src/server/android/driver/app/src/androidTest/java/com/microsoft/playwright/androiddriver/InstrumentedTest.java @@ -16,11 +16,13 @@ package com.microsoft.playwright.androiddriver; +import android.bluetooth.BluetoothClass; import android.graphics.Point; import android.graphics.Rect; import android.net.LocalServerSocket; import android.net.LocalSocket; import android.os.Bundle; +import android.view.accessibility.AccessibilityNodeInfo; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SdkSuppress; @@ -30,6 +32,7 @@ import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.Direction; import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.UiSelector; import androidx.test.uiautomator.Until; import org.json.JSONArray; @@ -42,7 +45,10 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.regex.Pattern; /** @@ -221,21 +227,25 @@ public class InstrumentedTest { wait(device, params).swipe(parseDirection(params), params.getInt("percent")); } + private static JSONObject serializeRect(Rect rect) throws JSONException { + JSONObject rectObject = new JSONObject(); + rectObject.put("x", rect.left); + rectObject.put("y", rect.top); + rectObject.put("width", rect.width()); + rectObject.put("height", rect.height()); + return rectObject; + } + private static JSONObject info(UiDevice device, JSONObject params) throws JSONException { - JSONObject info = new JSONObject(); UiObject2 object = device.findObject(parseSelector(params)); - Rect bounds = object.getVisibleBounds(); - JSONObject boundsObject = new JSONObject(); - boundsObject.put("x", bounds.left); - boundsObject.put("y", bounds.top); - boundsObject.put("width", bounds.width()); - boundsObject.put("height", bounds.height()); + + JSONObject info = new JSONObject(); info.put("clazz", object.getClassName()); info.put("pkg", object.getApplicationPackage()); info.put("desc", object.getContentDescription()); info.put("res", object.getResourceName()); info.put("text", object.getText()); - info.put("bounds", boundsObject); + info.put("bounds", serializeRect(object.getVisibleBounds())); info.put("checkable", object.isCheckable()); info.put("checked", object.isChecked()); info.put("clickable", object.isClickable()); @@ -248,6 +258,26 @@ public class InstrumentedTest { return info; } + private static JSONObject info(AccessibilityNodeInfo node) throws JSONException { + JSONObject info = new JSONObject(); + Rect bounds = new Rect(); + node.getBoundsInScreen(bounds); + info.put("desc", node.getContentDescription()); + info.put("res", node.getViewIdResourceName()); + info.put("text", node.getText()); + info.put("bounds", serializeRect(bounds)); + info.put("checkable", node.isCheckable()); + info.put("checked", node.isChecked()); + info.put("clickable", node.isClickable()); + info.put("enabled", node.isEnabled()); + info.put("focusable", node.isFocusable()); + info.put("focused", node.isFocused()); + info.put("longClickable", node.isLongClickable()); + info.put("scrollable", node.isScrollable()); + info.put("selected", node.isSelected()); + return info; + } + private static void inputPress(UiDevice device, JSONObject params) throws JSONException { device.pressKeyCode(params.getInt("keyCode")); } @@ -273,6 +303,35 @@ public class InstrumentedTest { device.drag(from.x, from.y, to.x, to.y, params.getInt("steps")); } + private static JSONObject tree(UiDevice device) throws JSONException { + return serializeA11yNode(getRootA11yNode(device)); + } + + private static AccessibilityNodeInfo getRootA11yNode(UiDevice device) { + try { + Method getQueryController = UiDevice.class.getDeclaredMethod("getQueryController"); + getQueryController.setAccessible(true); + Object queryController = getQueryController.invoke(device); + + Method getRootNode = queryController.getClass().getDeclaredMethod("getRootNode"); + getRootNode.setAccessible(true); + return (AccessibilityNodeInfo) getRootNode.invoke(queryController); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + return null; + } + } + + private static JSONObject serializeA11yNode(AccessibilityNodeInfo node) throws JSONException { + JSONObject object = info(node); + if (node.getChildCount() == 0) + return object; + JSONArray children = new JSONArray(); + object.put("children", children); + for (int i = 0; i < node.getChildCount(); ++i) + children.put(serializeA11yNode(node.getChild(i))); + return object; + } + @Test public void main() { UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); @@ -352,6 +411,9 @@ public class InstrumentedTest { case "inputDrag": inputDrag(device, params); break; + case "tree": + response.put("result", tree(device)); + break; default: }