
    Ajd                       d dl Z d dlZd dlZd dlmc mZ d dlmZ d dl	Z	d dl
Z
d dlZ ee      j                         j                  j                  Z ee      e	j"                  vr"e	j"                  j%                  d  ee             d dl d dlmZ d dlmZ d dlmZ dZdZd	Zd
ZdZe dZ edz  dz  Z! G d de"      Z#da$d Z%d Z&defdZ'eefdedede(fdZ)eefdede(dede(fdZ*de+fdZ,dede+fdZ-e!fdedefd Z.defd!Z/e!fd"edefd#Z0e!fd"efd$Z1d%efd&Z2dd'e(fd(Z3d)efd*Z4d+ Z5d, Z6defd-Z7dd/ed0e8fd1Z9dd/ed0e8fd2Z:dd/ed0e8fd3Z;defd4Z<d5d6d7d8d9d:d;d<d=d>d?
Z=dd@ede8fdAZ>dBefdCZ?dDefdEZ@d@efdFZAdBedGe(de8fdHZBdDede8fdIZCdDede8fdJZDdK ZEdL ZFdMedefdNZGdO ZHddPe(fdQZIdRefdSZJdTZKd@ede8fdUZLded@efdVZMdRefdWZNdRefdXZOdRefdYZPdRefdZZQdRefd[ZRd\ ZSd] ZTde8fd^ZUde(fd_ZVdd`e(dae(dbe(fdcZWddde(fdeZXdf ZYddPe(fdgZIdh ZZdRefdiZ[dddd.djdkZ\dddd.djdlZ]de8fdmZ^ddnede8fdoZ_ddnedde(de8fdpZ`de8fdqZadr Zbddsecde8fdtZdduede8fdvZeddsecde8fdwZfddDedxe(de8fdyZgdz Zhdefd{Zidd|ecde8fd}Zjd~ Zkddecde8fdZld Zmd ZndedefdZod@ededepfdZqdde(fdZrdde(d0e8de8fdZsdefdZtdede8fdZuddede(de8fdZvd Zwd Zxd Zyddede(de8fdZzd Z{defdZ|dede}fdZ~dededefdZddZddedsecdecde8fdZddedede8fdZg dZdZdZeefdedede(fdZddedde(decfdZdepdefdZ e j                  de j                         e j                  de j                        gZddde(decddfdZddde(ddfdZdee(e(f   fdZddZddZde8fdZddsecde8fdZdefdZd Zde8fdZde8fdZddZdede8fdZedk(  r	 ed       yy)    N)Path)*)Client)Image)tap_one_pointz153.80.251.46i  z	127.0.0.1i  zru.ozon.fintech.financezE/ru.ozon.fintech.features.tabber.presentation.finance.FinanceActivitytempzui_dump.xmlc                       e Zd ZdZy)ActionCancelleduR   Действие панели принудительно отменено из UI.N)__name__
__module____qualname____doc__     -/var/www/oz-panel.ru/ozpay-pub/server/main.pyr
   r
      s    \r   r
   c                     | a y)uY   Подключить проверку отмены (вызывается панелью).N_action_cancel_hook)hooks    r   set_action_cancel_hookr   #   s
     r   c                  &    t         t                y y Nr   r   r   r   check_action_cancelledr   )   s    & 'r   msgc                     t         j                   j                         j                  d      }t        d| d|         t	                y )Nz%Y-%m-%d %H:%M:%S[z] )datetimenowstrftimeprintr   )r   tss     r   logr"   .   s<    						 	)	)*=	>B	AbTC5/r   device_nameadb_hostadb_portc           	      t   t                t        ||      }t        |       }t        |       }||t	        d| d|d|      	 t        |      }	 |j                         }|D ]+  }|j                  | d| k(  st        d| d|        |c S  	 ddl
}	 |j                  |t        |      fd	
      5  	 ddd       	 |j                  ||       |j                  | d|       }
|
;|j                         D cg c]  }|j                   }}t	        d| d| d|       t        d| d|        |
S # t        $ r Y w xY w# t        $ r g }Y w xY w# 1 sw Y   xY w# t        $ r}	t	        d| d| d|	       d}	~	ww xY w# t        $ r}	t        d| d| d|	        Y d}	~	d}	~	ww xY wc c}w )u:   Подключиться к Redroid через ADB daemon.hostportNu   У устройства u8    не указаны IP или порт в базе: ip=z, port=:uC   Подключено к уже-существующему Redroid: r      timeoutzRedroid u-    недоступен (socket probe failed): u4   Предупреждение: remote_connect для     не удался: u8   Не удалось подключиться к Redroid 1   . Подключенные устройства: u!   Подключено к Redroid: )r   	AdbClientget_ipget_portRuntimeErrorint	Exceptiondevicesserialr    socketcreate_connectionremote_connectdevice)r#   r$   r%   clientr(   r)   	connecteddr8   excr;   s              r   connect_redroidr@   4   sH   H84F+DK D|t|5k_D|  ~B  }E  EL  MQ  LT  U  V  	V4y
NN$	 	AxxdV1TF++[\`[aabcgbhij	 g%%tSY&7%C 		
mdD) ]]dV1TF+,F~'-~~'78!QXX8	8FtfAdV T>>G[J
 	

 
-dV1TF
;<MI    		 	 gXdV1TF2_`c_deffg
  mDTF!D6Qefiejkllm
 9s~   D: )E	 =E	 E	 E& 7E9E& F >F5:	EE	EEE#E& &	F/FF	F2F--F2r(   r)   c                    ddl }| xs dj                         } 	 t        |      }| st        d      |  d| }t        ||      }	 |j                         D ]$  }|j                  |k(  s|j                  d        y	 	 	 |j                  | |fd
      5  	 ddd       	 |j                  | |       |j                  |      }|;g }		 |j                         D 
cg c]  }
|
j                   }	}
t        d| d|	       	 |j                  d       y	# t        t        f$ r}t        d      |d}~ww xY w# t        $ r Y w xY w# 1 sw Y   xY w# t        $ r}t        d| d|       |d}~ww xY w# t        $ r}t        d| d|       |d}~ww xY wc c}
w # t        $ r Y w xY w# t        $ r}t        d| d|       |d}~ww xY w)ub   Проверить, что host:port доступен через ADB. Без записи в БД.r   N u+   Порт должен быть числомu   Укажите IPr*   r'   echo okTr+   r,   u0   Не удалось подключиться к : u   ADB connect к r.   r/   u	   ADB на u    не отвечает: )r8   stripr4   	TypeError
ValueErrorr3   r0   r6   r7   shellr5   r9   r:   r;   )r(   r)   r$   r%   r8   r?   r7   r<   r;   r=   items              r   	probe_adbrJ   f   s/   JBDS4y .//vQtfFH84Fnn& 	F}}&Y'	h%%tTlA%> 		
YdD) ]]6"F~		171ABBIB >vh G>>G[J
 	

WY W z" SHIsRS  	 	 hMfXUWX[W\]^dggh
  Y_VH4HNOUXXY C 		  WYvh.FseLMSVVWs   D "D6 *D6 =D6  E EE  E4 F F-F F+ D3"D..D36	EEE
E 	E1E,,E14	F=FFF 	F('F(+	G4GGreturnc                 R    | j                         }|st        d      t        |      S )u_   Снять скриншот экрана устройства и вернуть PNG-байты.u.   screencap вернул пустой ответ)	screencapr3   bytes)r;   datas     r   screencap_pngrP      s)    DKLL;r   c                 0    t        |       }t        |      S )uv   Подключиться к устройству и вернуть PNG-скриншот текущего экрана.r#   )r@   rP   r#   r;   s     r   capture_screenrT      s    5F  r   
local_pathc                 D   t                d}t        |      }|j                  j                  dd       	 | j	                  d       | j                  |t        |             |j                         st        d|       |S # t        $ r}t        d|         d}~ww xY w)uj   Получить XML-дамп UI hierarchy с устройства и сохранить локально.z/sdcard/ui.xmlT)parentsexist_okzuiautomator dump /sdcard/ui.xmlu(   uiautomator dump не сработал: Nu'   Файл дампа не найден: )r   r   parentmkdirrH   pullstrr5   r    existsFileNotFoundError)r;   rU   remote_pathr?   s       r   dump_ui_xmlr`      s    "Kj!JD4867KZ1
 "I* VWW  8>?s   ,B 	BBBc                 .    t        |       }t        |      S )ue   Одна функция: возвращает текст среды из XML-дампа UI hierarchy.)r`   read_dump_text)r;   	dump_paths     r   get_dump_textrd      s    F#I)$$r   pathc                    t        j                  |       }|j                         }g }|j                         D ]  }dD ]  }|j                  j                  |      }|s!|j                         s2dj                  |j                               }t        |      dk\  s`|j                  d      rr|j                  |         dj                  t        j                  |            S )uH   Вернуть чистый текст из XML-дампа UI hierarchy.textcontent-desc    android.
)ETparsegetrootiterattribgetrE   joinsplitlen
startswithappenddictfromkeys)re   treeroottextsnodeattrvaluecleans           r   rb   rb      s    88D>D<<>DE		 (, 	(DKKOOD)E/u:?5+;+;J+GLL'	(( 99T]]5)**r   c                 L    t        j                  |       }|j                         S )uC   Возвращает XML root из локального дампа.)rn   ro   rp   )re   r{   s     r   get_dump_rootr      s    88D>D<<>r   boundsc                     | sy	 t        t        t        j                  d|             \  }}}}||z   dz  ||z   dz  f}||z   dz  |t        d||z
  dz        z   f}||||||dS # t        $ r Y yw xY w)u   Парсит bounds из XML вида 'left top right bottom' и возвращает центр и верхнюю середину.Nz-?\d+rk   
   )lefttoprightbottomcenter
top_center)mapr4   refindallrG   max)r   r   r   r   r   r   r   s          r   parse_boundsr      s    #&sBJJx,H#I c5& e|!C&LQ#67F%<A%sSVc\b4H-I'IJJ  	  s   )A$ $	A0/A0min_yc                 x    | sy| d   | d   z
  }| d   | d   z
  }|dk  s|dk  ry| d   \  }}|d	k  s||k  ry||fS )
u~   Точка нажатия только для реально видимого узла, не [0,0] и не статусбар.Nr   r   r   r   (      r      r   )r   r   widthheightxys         r   usable_tap_pointr      sd    7OfVn,EHu-FrzVb[(DAq2vUq6Mr   r   c                 `   | sy| j                         j                         }t        j                  d|t        j                        }|r|j                  d      j                         n|}ddddd	d
ddddd
}ddddd	d
ddddd
}t        j                  d|      r|S ||v r||   S ||v r||   S y)uf   Normalize UI text like 'цифра 0', 'цифра ноль', 'digit zero' to a single digit '0'..'9'.Nu   (?:цифра\s*|digit\s*)?(.*)flags   0123456789)
zeroonetwothreefourfivesixseveneightnine)
u   нольu   одинu   дваu   триu   четыреu   пятьu
   шестьu   семьu   восемьu   девятьz[0-9])rE   lowerr   	fullmatch
IGNORECASEgroup)r   smcoreen_wordsru_wordss         r   _text_to_digitr      s    A
7"--PA!"1771:D Cc3C#SH
 SC3X[sSbeH 
||Hd#x~x~r   c                 n   dx}}t        |      dk(  r|d   }t        |t        t        f      r+t        |      dk\  rt	        |d         t	        |d         }}nt        |t
              rd|v r<t        |d   t        t        f      r#t	        |d   d         t	        |d   d         }}nd|v r<t        |d   t        t        f      r#t	        |d   d         t	        |d   d         }}nPd|v rLd|v rHt	        |d         t	        |d         }}n+t        |      dk\  r	 t	        |d         t	        |d         }}||t        d	|        yt                t        d
| d|        	 | j                  d| d|        y# t        $ r dx}}Y Vw xY w# t        $ r}t        d|        Y d}~yd}~ww xY w)up  Нажимает на координату на экране.

    Поддерживает вызовы в трёх форматах:
    - `tap_screen_point(device, x, y)`
    - `tap_screen_point(device, (x, y))` или `tap_screen_point(device, [x, y])`
    - `tap_screen_point(device, bounds_dict)` где `bounds_dict` — результат `parse_bounds()`
    Nr   r   rk   r   r   r   r   z+tap_screen_point: invalid coordinates args=ztap_screen_point: x=z y=z
input tap rj   ztap failed: )
rv   
isinstancetuplelistr4   ry   r5   r"   r   rH   )r;   argsr   r   vr?   s         r   tap_screen_pointr     s    LA
4yA~Ga%'CFaKqt9c!A$iqA4 1}AhK%!G1X;q>*C(A,?1"z!L/E4='Q1\?1-.AlOA4F0G1 Q;5A:qy>3qx=qA	Ta	tAw<T!WqA 	yAI9$@A
qcQC()"z!AaS)*  	LA	  "l3% !!"s*   F  (F  FF	F4F//F4c                     t                t        d       	 | j                  d       y# t        $ r}t        d|        Y d}~yd}~ww xY w)u)   Нажимает кнопку назад.zpress_back: sending keyevent 4zinput keyevent 4zpress_back failed: N)r   r"   rH   r5   )r;   r?   s     r   
press_backr   D  sF    ())'( )!#'(()s   ) 	A
AA
c                 2    t        |       }t        |       y)up   Подключиться к устройству и нажать системную кнопку «Назад».rR   N)r@   r   rS   s     r   press_device_backr   N  s    5Fvr   Ftext_patternexactc           
         t        |       }t        d|        t        |      }t        j                  |dd      }t        d|dd         g }g }g }	|j                         D ]6  }
|D ]-  }|
j                  j                  |      }|"dj                  |j                               }|r|j                  d	      rU|	j                  |       	 |r"|j                         |j                         k(  }n(t        j                  ||t        j                  
      du}|st#        |
j                  j                  d            }||d   }|d   dk(  r-|d   dk(  r%t        d| d       |j                  |d|f       |j                  ||d   |f       0 9 |r%|d   \  }}}t        d|d| d| d|        |||fS |r%|d   \  }}}t        d|d| d| d|        |||fS |	rBdj                  t%        t&        j)                  |	            dd       }t        d|d|        yt        d|d       y# t        j                   $ r$ |j                         |j                         v }Y Yw xY w)u   Ищет UI-элемент по тексту/description в текущем дампе и возвращает (text, center, attr).z#find_ui_element_by_text: dump_path=unicodexml)encodingmethodz'find_ui_element_by_text: dump preview:
Ni  rj   rl   r   r   r   r   r   z find_ui_element_by_text: found 'z7' but center is (0,0), marking as zero-center candidater   r   r   z!find_ui_element_by_text: pattern=z -> found 'z'='z' at top_center=z! -> found zero-center candidate ',    z not found. candidates=z# not found. dump has no text fields)r`   r"   r   rn   tostringrq   rr   rs   rt   ru   rw   rx   r   r   searchr   errorr   r   ry   rz   )r;   r   attrsr   rc   r|   	dump_textmatchesmatches_zerocandidate_textsr~   r   r   rh   okr   r   	tap_pointpreviews                      r   find_ui_element_by_textr   T  s   F#I
-i[9:#DD9UCI
29Ud3C2DEFGLO		 ? 	?DKKOOD)E}88EKKM*D4??:6""4(:););)==B<R]]KSWWB !$++//(";<F~H%FayA~&)q.6tf<stu##T64$89NND&"6=>=	??B  '
i//?{4&PSTXSYYijsituvY$$  ,Qi//??`ae`ffijnioo  AJ  @K  L  	MY$$))D!?@"EF//??VW^V_`a  	//??bcdE 88 :!'')TZZ\9:s   AI  3I76I7c                    d}	 t        | |||      }|sy|\  }}}t        |t        t        f      rut	        |      dk\  rg|d   dk(  r_|d   dk(  rWt        d| d|dz    d	       	 | j                  d
       t        j                  d       |dz  }|dkD  rt        d| d       yt        | g|  y# t        $ r}t        d|        Y d}~Yd}~ww xY w)u   Находит UI-элемент по тексту/description и нажимает в верхнюю середину элемента.r   Tr   r   Frk   r   z"find_and_tap_ui_element: element 'z.' center is (0,0), swiping to reveal (attempt )zinput swipe 700 900 700 300z'find_and_tap_ui_element: swipe failed: N       @r   z)find_and_tap_ui_element: giving up after  swipes)r   r   r   r   rv   r"   rH   r5   timesleepr   )	r;   r   r   r   attemptsresult_r   r?   s	            r   find_and_tap_ui_elementr     s    H
(URWX 9ai%/C	Na4GIVWL\]L]bklmbnrsbs4\NBpqyz{q{p||}~E:< JJsOMH"}?zQR,),  E=cUCDDEs   &B4 4	C=CCc                      t        | |||      S )uU   Совместимая обертка для старого вызова tap_by_text.r   )r   )r;   r   r   r   s       r   tap_by_textr     s    "6<uERRr   c                  X   t         j                  j                  d      } | r| S t        d      t        dz  t        t
              j                         j                  dz  g}|D ]5  }|j                         s	 |j                  d      j                         c S  y# t        $ r Y  yw xY w)u   Попытаться получить пароль из переменной окружения `LK_PASSWORD` или файла `password.txt`.LK_PASSWORDzpassword.txtzutf-8)r   N)osenvironrs   r   _ROOT__file__resolverY   r]   	read_textrE   r5   )pwdcandidate_pathspw_files      r   _get_password_from_env_or_filer     s    
**..
'C

 	^X ''.8O
 # >>(('(:@@BB   s   8B	B)(B))x     )h  r   )X  r   )r   r   )r   r   )r   r   )r      )r   r   )r   r   )r   i  )
r   r   r   r   r   r   r   r   r   r   r   c                 b    | xs dj                         syg d}t        fd|D              S )u   Экран блокировки, если в XML есть явные подписи цифр: 'цифра один', 'цифра 1', 'digit one', 'digit 1' и т.п.rB   F)u   \bцифра\s*(?:один|1)\bu   \bцифра\s*(?:два|2)\bu   \bцифра\s*(?:три|3)\bu#   \bцифра\s*(?:четыре|4)\bu   \bцифра\s*(?:пять|5)\bu!   \bцифра\s*(?:шесть|6)\bu   \bцифра\s*(?:семь|7)\bu#   \bцифра\s*(?:восемь|8)\bu#   \bцифра\s*(?:девять|9)\bu   \bцифра\s*(?:ноль|0)\bz\bdigit\s*(?:one|1)\bz\bdigit\s*(?:two|2)\bz\bdigit\s*(?:three|3)\bz\bdigit\s*(?:four|4)\bz\bdigit\s*(?:five|5)\bz\bdigit\s*(?:six|6)\bz\bdigit\s*(?:seven|7)\bz\bdigit\s*(?:eight|8)\bz\bdigit\s*(?:nine|9)\bz\bdigit\s*(?:zero|0)\bc              3   j   K   | ]*  }t        j                  |t         j                          , yw)r   N)r   r   r   .0patternrh   s     r   	<genexpr>z&is_lock_screen_text.<locals>.<genexpr>  s%     Yryy$bmm<<Ys   03)r   any)r   r|   digit_labelsrh   s      @r   is_lock_screen_textr    s5    O""$DL, YLYYYr   digitc                    t        |       }t        |      }d}|j                         D ]  }dD ]y  }|j                  j	                  |      xs dj                         }|s3t        |      }|A|t        |      k(  sPt        |j                  j	                  d            }	|	sw|	} n |s n |t        d|d      t        d| d|        t        | |       t        j                  d	       y)
uq   Нажимает цифру по UI-элементу, а не по статическим координатам.Nrh   ri   hintrB   r   u6   Не найден UI-элемент для цифры u'    на экране блокировкиz
Tap digit=z via UI element at center=g333333?)r`   r   rq   rr   rs   rE   r   r\   r   rG   r    r   r   r   )
r;   r  rc   r|   targetr~   r   r   mappedr   s
             r   tap_pin_digitr    s   F#I#DF		 4 		D[[__T*0b779E#E*F!fE
&:%dkkooh&?@#F		  ~QRWQZ  [B  C  D  	D	Jug7x
@AVV$JJsOr   passwordc                 H    | g S t        j                  dt        |             S )uY   Приводит пароль к списку цифр: '1 5 7 3' -> ['1', '5', '7', '3']z\d)r   r   r\   )r  s    r   _normalize_password_digitsr    s"    	::eS]++r   c                     | syt        j                  d| t         j                        }|syt        |j	                  d            t        |j	                  d            fS )ug   Возвращает (введено, всего) по строке 'Введено 1 из 4 цифр'.r   u0   введено\s+(\d+)\s+из\s+(\d+)\s*цифрr   r   rk   )r   r   r   r4   r   )r   matchs     r   parse_entered_pin_countr    sM    III9\^\i\ijEu{{1~EKKN 333r   expected_countc                    t        t        |             \  }}||k\  ryt        | |       	 t        |       }t        d       t        |       t        j
                         dz   }t        j
                         |k  r	 t        |       }t        |      \  }	}
|
r|	|k(  rt        d|	 d|
 d	       y|
d
k(  r|r||k(  rt        d       y|	|kD  rt        d| d|	 d|        yt        j                  d       t        j
                         |k  rt        d| d|        y# t        $ r}t        d|        Y d}~d}~ww xY w# t        $ r t        j                  d       Y w xY w)u   Нажимает цифру, ждёт появления нужного count и возвращает True только при успешном вводе.Tu*   === Дамп после нажатия ===uI   Не удалось получить дамп после нажатия: N      @皙?u!   Проверка: введено u    из u	    цифрr   u   Проверка: счётчик пропал после последней цифры — считаем ввод успешнымu=   Слишком много цифр после нажатия rD   z > Fu   После нажатия uM    не появился ожидаемый счётчик: ожидалось )r  rd   r  r    r5   r   r   )r;   r  r  before_countbefore_total	post_dumpr?   deadliner   current_counttotals              r   tap_pin_digit_and_waitr  %  s   !8v9N!OL,~%&% a!&)	:;i yy{S H
))+
 	%f-I
  7yAu]n45m_F5'QZ[\ A:,>\+I  X  Y>)QRWQXXZ[hZiilm{l|}~

3+ ))+
 . 
&ug-z  |J  {K  L  M9  aYZ]Y^_``a  	JJsO	s)   !D ;E 	E (D;;E E%$E%c           	         t        |      }|syt        |       }t        |      syt        d|        |D ]$  }	 t	        | |       t        j                  d	       & y
# t
        $ r}t        j                  t        |            }|rKt        d| d|        	 t        | g|  nC# t
        $ r }t        d| d|        Y d}~Y d}~ yd}~ww xY wt        d| d|        Y d}~ yY d}~d}~ww xY w)u  Если открылся экран пароля — просто вводит PIN по UI-элементам, без проверки счётчика.

    Каждая цифра нажимается по своему UI-элементу; при отсутствии элемента — по
    статическим координатам. Счётчик 'Введено X из Y' не проверяется.
    FzPIN order: zFallback: tap coords for digit=z at u=   Не удалось нажать координаты для rD   Nua   Ошибка: не найден UI-элемент и нет координат для цифры r  T)r  rd   r  r    r  r5   PIN_KEY_COORDSrs   r\   r   r   r   )r;   r  r   r   r  r?   coordsexc2s           r   enter_lock_passwordr"  Q  s$    %X
.Cf%Iy)	Ku
 	&%( 	

3"   	#''E
3F7wd6(KL!$V5f5  !YZ_Y``bcgbhij 5! yz  zA  AC  DG  CH  I  J 6	sA   A	C3'1C.B&%C.&	C/C
 C.
CC..C3c                    	 t        |       }t        |      }t        |      }t	        ||      syt        d       t        d|        t        | |      }|rt        d| d       yt        d| d	       y# t        $ r Y yw xY w)
uu   Если приложение на экране пароля, вводит пароль и возвращает True.F)r|   u7   ЛК находится на экране пароля.u#   Используем пароль: u   Пароль u    успешно введён.Tu.   Не удалось ввести пароль .)r`   r   rb   r5   r  r    r"  )r;   r  rc   r|   r   r   s         r   ensure_lock_screen_unlockedr%  t  s    '	Y'"9-	 yt4 

CD	/z
:;	VX	.B	hZ'DEF	:8*A
FG!  s   !A8 8	BBc                 h   g }| j                         D ]  }|j                  j                  d      dk(  r|j                  |       4|j                  j                  dd      xs d}|j                  j                  dd      xs d}|j                  j                  d      xs< |j                  j                  d      xs |j                  j                  d      xs d}d	|v s:d|j	                         v s(t        j                  d
|t
        j                        s|j                  |        |S )uo   Найти узлы, соответствующие полю ввода пароля/пина в дампе UI.r  trueclassrB   resource-idrh   ri   r	  EditTextu"   парол|pin|код|password|pinr   )rq   rr   rs   rx   r   r   r   r   )r|   nodesr~   clsresourcerh   s         r   find_password_nodesr.    s    E		 ;;??:&&0LLkkoogr*0b;;??="5;'k4;;??>+Jkdkkoo^dNekik
hnn.> >"))Lqsw  @B  @M  @M  CNLL Lr   c                 Z   i }| j                         D ]  }dD ]  }|j                  j                  |      xs d}t        |      }|1|j                  j                  d      xs dj	                         }|j                  j                  d      xs d}|dk7  rt        j                  d|      s|j                         j	                         }t        j                  d|t
        j                        rt        |j                  j                  d	            }	|	s|	||<      |S )
u   Найти кнопку-клавиши цифровой клавиатуры на экране и вернуть словарь digit->(x,y).r  rB   	clickabler(  r'  zButton|ImageButton|ImageViewuT   выйти|не помню|непомню|код‑пароль|код-?парольr   r   )
rq   rr   rs   r   r   r   r   rE   r   r   )
r|   keysr~   r   r   r  r0  r,  lowr   s
             r   find_key_nodesr3    s   D		 4 	DKKOOD)/RE"5)E}5;BBDI++//'*0bCF"2995TVY+Z++-%%'Cyypru}  ~K  ~K  L!$++//(";<F$U#	( Kr   r   c                 L    | y| j                  dd      j                  dd      S )u\   Экранирует текст для `adb shell input text` (простой подход).rB   %z%25rj   z%s)replace)r   s    r   _adb_escape_textr7    s(    y99S% ((d33r   c                 J   g }| j                         D ]  }dD ]  }|j                  j                  |      }|s!dj                  |j	                               }|j                  d      rRt        j                  d|t        j                        syt        |j                  j                  d            }|s|j                  ||f         g }|D ]L  \  }}|j                         t        fddD              r+t        |      d	k  r:|j                  ||f       N |S )
uu   Находит карточки на текущем экране по тексту и/или цифрам карты.rg   rj   rl   u;   (?:Bank\s+Card|Карта|Visa|Mastercard|Мир|MIR|\d{4})r   r   c              3   &   K   | ]  }|v  
 y wr   r   )r   tokenr   s     r   r  z"find_card_nodes.<locals>.<genexpr>  s       u%u~  u   )u   показатьu   добавить   настройкиu   меню   главная   аккаунт   счёт
   выход   оплатить   перевести   пополнитьr+   )rq   rr   rs   rt   ru   rw   r   r   r   r   rx   r   r  rv   )	r|   
candidatesr~   r   r   rh   r   filteredr   s	           @r   find_card_nodesrF    s   J		 6, 
	6DKKOOD)E88EKKM*Dz*yyWY]egerers%dkkooh&?@%%vtn5
	66 H" (

  u  ,t  u  ut9q='( Or   	max_cardsc                    g }t               }t        |      D ]  }t        |       }t        |      }t	        |      }|sBt        |      }t        |      }	|	d   s|	d   s
|	d   s|	d   r|j                  ddi|	        |S |d   \  }
}t        j                  dd	|      j                         }||v r |S |j                  |       t        | |
       t        |       }t        |      }t        j                  d
|t        j                        r%t        | d
      s |S t        |       }t        |      }t        |      }	|	d   s|	d   s
|	d   s|	d   r|j                  d|i|	       t!        |        t        |       }t        |      }t        j                  d
|t        j                        st	        t        |            rt!        |         |S )u   Открывает каждую карту, нажимает Показать, парсит данные и возвращается назад.card_number
card_last4expirycvv
card_labelcurrentr   \s+rj      Показать|Showr   )setranger`   r   rF  rb   parse_card_datarx   r   subrE   addr   r   r   r   r   )r;   rG  resultsseenr   rc   r|   cardscurrent_textparsedr   labelcard_keydetail_pathdetail_text	next_dump	next_texts                    r   parse_all_cardsra    s   G5D9 &'	Y'%))4L$\2Fm$|(<x@PTZ[`TaiB6BC< N9 a66&#u-335t2 N1 	 	(!&)$[199-{"--Pv'?@ N &f-K(5K -- F<$8F8<LPVW\P]NNL(=f=>6'	"9-	99-yNWfgtu~g  XAvM&P Nr   rh   c                 8   h d}| j                         D ]  }dj                  |j                               }|rt        |      dk  r3|j	                         t        fd|D              rXt        j                  d|      sot        j                  d|      r|j                         c S t        j                  d|      s|j                         c S  g d}|D ];  }t        j                  ||       }|s|j                  d	      j                         c S  y
)u   Извлекает имя владельца аккаунта, например: 'Евгений Ляпин' или 'Евгений Л.'.>   	   картa
   выйти   баланс   профиль   подписка   мои документы   основной счётr?  r>  rA  rB  rC  rj   r+   c              3   &   K   | ]  }|v  
 y wr   r   )r   wordr   s     r   r  z-extract_account_owner_name.<locals>.<genexpr>#  s     1tu}1r;  u   [А-ЯЁа-яё]u!   [А-ЯЁ][а-яё]+\s+[А-ЯЁ]\.uE   [А-ЯЁ][а-яё]+(?:\s+[А-ЯЁ][а-яё]+){1,2}(?:\s+[А-ЯЁ]\.)?)u'   (?m)^[А-ЯЁ][а-яё]+\s+[А-ЯЁ]\.$u=   (?m)^[А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё]+\s+[А-ЯЁ]\.$u/   (?m)^[А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё]+$uE   (?m)^[А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё]+$r   N)
splitlinesrt   ru   rv   r   r  r   r   r   rE   r   )rh   blockedline	candidatepatternsr  r  r   s          @r   extract_account_owner_namerq    s    G ! %HHTZZ\*	C	NQ.!111yy,i8<<<iH??$$<<`bkl??$$%H  *		'4(;;q>''))* r   )u.   операци\w*\s+приостановленu+   причины и как исправитьu'   сч[её]т\s+заблокированu)   аккаунт\s+заблокированu+   карт[аыу]\s+заблокированc                     | xs dj                         j                  dd      j                  dd      j                         syt        fdt        D              S )ur   Блок Ozon по фразам с экрана, например 'Операции приостановлены'.rB       rj   u    Fc              3   J   K   | ]  }t        j                  |        y wr   )r   r   r   s     r   r  z'is_ozon_blocked_text.<locals>.<genexpr>G  s     KGryy$'Ks    #)r   r6  rE   r  OZON_BLOCK_PATTERNS)r   rh   s    @r   is_ozon_blocked_textrv  B  sM    O""$,,VS9AA(CPD::<K7JKKKr   c                     |xs dj                         rt        |      ryt        |      }t        | |rdnd       |rt	        d|  d       |S )u|   Сохранить в БД, заблокирован ли Ozon. Пустой дамп и экран PIN не трогаем.rB   Nr   r   zOzon blocked for u/   : операции приостановлены)rE   r  rv  update_blockedr"   )r#   r   rm  s      r   sync_ozon_blockedry  J  sP    O""$(;I(F"9-G;W!4},[\]Nr   c                     t        |       }d}t        j                  d| t        j                        }|r3|j	                  d      j                         j                  dd      xs d}||dS )uq   Парсит баланс и имя аккаунта. Если данных нет — возвращает None.Nuc   (?:Баланс|Остаток|Основной\s+счёт|Счёт)\s*[:\-]?\s*(\d[\d\s.,]*)\s*₽r   r   rj   rB   )account_namebalance)rq  r   r   r   r   rE   r6  )rh   r{  r|  balance_matchs       r   parse_balance_and_account_namer~  U  s{    -d3LGII  E  GK  SU  S`  S`  aM%%a(..088bAIT(W==r   c                 L   t        |       }d}t        j                  d|       }|rB|j                  d      j	                  dd      j	                  dd      j	                  dd      }n9t        j                  d|       }|r!|j                  d      j	                  dd      }||d	S )
uX   Парсит номер карты и имя аккаунта. Если нет — None.N3\+7\s*\(?\d{3}\)?\s*\d{3}\s*[- ]?\d{2}\s*[- ]?\d{2}r   rj   rB   (r   z\b(?:\d{4}\s?){4}\b)r{  number)rq  r   r   r   r6  )rh   r{  r  phone_matchnumber_matchs        r   parse_number_and_account_namer  a  s    -d3LF))RTXYK""1%--c26>>sBGOOPSUWXyy!7>!''*223;F(F;;r   c                     t        j                  d|       }|rA|j                  d      j                  dd      j                  dd      j                  dd      S y)u^   Парсит номер телефона из dump. Если телефона нет — None.r  r   rj   rB   r  r   N)r   r   r   r6  )rh   r  s     r   parse_phone_numberr  q  sS    ))RTXYK  #++C4<<S"EMMcSUVVr   c                 V   ddddddd}d}t        j                  ||       r|S t        j                  d|       }|r@|j                  d      j                  dd      j                  dd      |d	<   |d	   d
d |d<   n<t        j                  d| t         j                        }|r|j                  d      |d<   t        j                  d|       }|r|j                  d      |d<   t        j                  d|       }|r|d   |j                  d      |d<   t        j                  d| t         j                        }|r"|j                  d      j                         |d<   t        j                  d| t         j                        }|r"|j                  d      j                         |d<   |S )uj   Парсит номер карты, срок, CVV, тип и last4. Если данных нет — None.N)rI  rJ  rK  rL  	card_typecard_variantr  z\b(?:\d{4}[- ]?){3}\d{4}\br   rj   rB   -rI  rJ  u?   (?:Bank\s+Card|Карта|MIR|Visa|Mastercard)[^\n\r]*(\d{4})\br   r   z%\b(?:0[1-9]|1[0-2])/(?:\d{2}|\d{4})\brK  z	\b\d{3}\brL  z<\bBank\s+Card\b|\bMIR\s+Pay\s+Ozon\b|\bVisa\b|\bMastercard\br  u[   Виртуальная\s+карта|Карта\s+в\s+мобильном\s+телефонеr  )r   r   r   r6  r   rE   )	rh   rO   phone_patternfull_number_matchlast4_matchexpiry_match	cvv_match
type_matchvariant_matchs	            r   rS  rS  y  s    D KM	yy%		"?F/55a8@@bIQQRUWYZ]!-05\ii bdhprp}p}~!,!2!21!5D99EtLL%++A.X		,-IT(^/ooa(UZ\`hjhuhuvJ&,,Q/557[II|  C  KM  KX  KX  YM,2215;;=^Kr   c                 H   dj                  | xs dj                               j                         } | r| j                  d      ryt	        j
                  d| t        j                        ryt	        j                  d| t        j                        }t        |      dk7  ry| S )	u   Возвращает корректный label карты, если текст содержит ровно одну карту; иначе None.rj   rB   rl   Nuw   Показать|Show|Детали|Оплатить|Перевести|Пополнить|Заказать\s+картуr   u0   (?:Bank\s+Card\s+\d{4}|Карта\s+\d{4}|\d{4})r   )	rt   ru   rE   rw   r   r   r   r   rv   )rh   card_patternss     r   normalize_card_labelr    s    88TZR&&()//1D4??:.	yy  L  NR  Z\  Zg  Zg  hJJRTX`b`m`mnM
=QKr   c                    g }| j                         D ]  }|j                  j                  d      xs |j                  j                  d      xs d}|sBdj                  |j	                               }t        |      }|sot        |j                  j                  d            }|st        |t              r|j                  d      n|}|s|d   dkD  s|d	   dkD  s|j                  ||d
        t               }g }	|D ].  }
|
d   }||v r|j                  |       |	j                  |
       0 t        |	d       S )uM   Находит кнопки карт на экране списка карт.rh   ri   rB   rj   r   r   r   r   r   r[  r   r[  c                 "    | d   d   | d   d   fS )Nr   r   r   r   )rI   s    r   <lambda>z#find_card_buttons.<locals>.<lambda>  s    DN1,=tH~a?P+Q r   )key)rq   rr   rs   rt   ru   r  r   r   ry   rx   rQ  rU  sorted)r|   buttonsr~   r   rh   r[  r   coordrW  uniquerI   r  s               r   find_card_buttonsr    s%   G		 B'P4;;??>+JPbxx&$T*dkkooh78,6vt,DFJJx(&E qB58b=%@A!B" 5DF 7m$;d &QRRr   c                    | j                         D ]  }|j                  j                  d      xs |j                  j                  d      xs d}|sBdj                  |j	                               }t        j                  ||t
        j                        st        |j                  j                  d            }|st        |t              r|j                  d      n|}|s|d   dk(  r|d	   dk(  rt        d
| d       ||dc S  y)u`   Ищет кнопку/текст по паттерну, например Показать, Show.rh   ri   rB   rj   r   r   r   r   r   zfind_button_by_label: found 'z' but center is (0,0), skippingr  N)rq   rr   rs   rt   ru   r   r   r   r   r   ry   r"   )r|   rp  r~   r   rh   r   r  s          r   find_button_by_labelr    s    		 8'P4;;??>+JPbxx&99Xt2==9!$++//(";<F0:640H

8,f8q=U1X]7v=\]^!%778 r   c                 n   	 t        |       }t        |      }t        |      }t        |      dk  ryd}|D ]3  }|d   }t        j                  d|t        j                        s/|dz  }5 |dk  rydj                  d	 |D              }d
D ]  }||v s y y# t        j                  t        f$ r Y yw xY w)u   Проверяет, что текущий экран — именно список карт, а не просто любой набор текста с цифрами.Frk   r   r[  u0   Bank\s+Card\s+\d{4}|Карта\s+\d{4}|\b\d{4}\br   r   rm   c              3   B   K   | ]  }|d    j                           ywr[  N)r   r   cards     r   r  z'screen_has_card_list.<locals>.<genexpr>  s     ?tG}**,?s   )	rA  rC  rB  u   главный экранu   контактыu   галереяzgoogle playr@  r<  T)r`   r   rn   
ParseErrorr^   r  rv   r   r   r   rt   )	r;   rc   r|   rX  
card_countr  r[  joinedr:  s	            r   screen_has_card_listr    s    '	Y' d#E
5zA~J W99H%WYWdWde!OJ
 A~YY???F
  F? ? MM,- s   B B43B4c                     	 t        |       }t        |      }t        t        |            S # t        j                  t        f$ r Y yw xY w)ur   Определяет количество открытых карт на текущем экране списка.r   )r`   r   rn   r  r^   rv   r  )r;   rc   r|   s      r   count_open_cardsr    sL    '	Y'  &'' MM,- s   , AAstart_yend_ystepsc                    t        |      D ]l  }| j                  d| d| d       t        j                  d       	 t	        t        |             }t        j                  d|t        j                        sl y y# t        $ r Y {w xY w)	u\   Физически прокручивает экран до блока реквизитов.zinput swipe 350 z 350 z 500皙?uk   Реквизиты|Показать|Show|Номер карты|CVV|Срок|Действительна доr   TF)
rR  rH   r   r   rb   r`   r5   r   r   r   )r;   r  r  r  r   rh   s         r   scroll_until_requisitesr    s    5\ 
'yeWDAB

3	!+f"56D 99  D  FJ  RT  R_  R_  `
   		s   A<<	BBr   c           	         t        j                  d|t         j                        }|r|j                  d      nd}t	        d      }d }t        |      D ]L  }	 t        t        |             }	|	t        t        |	            dk\  r6t        | g|  t        j                  d       	 t        t        |             }	|	t        |	d	      nd}
|
s2t!        | d
       	 t        t        |             }	|	t        |	d	      nd}
|
r$t        | g|
d     t        j                  d       t        d      D ]c  }t	        t#        t        |                   }|r
|d   s||d<   t%        |      t%        |      kD  r|} ||      r nt        j                  d       e  ||      sM n |r
|d   s||d<   |S # t        j                  $ r d}	Y ]w xY w# t        j                  $ r d}	Y *w xY w# t        j                  $ r d}	Y w xY w)ut  Открывает карту из карусели, доходит до реквизитов, жмёт Показать и парсит.

    Детальный экран может открыться не с первого тапа, кнопка «Показать» иногда
    ещё не размечена (bounds=[0,0]), а номер/срок/CVV появляются не мгновенно и
    могут снова скрыться. Поэтому делаем несколько попыток и быстро опрашиваем дамп
    сразу после нажатия «Показать».
    u*   (?:Bank\s+Card\s+|Карта\s+)?(\d{4})\br   r   NrB   c                 (    | d   xr | d   xr | d   S )NrI  rK  rL  r   rZ  s    r   	_completez'_open_and_parse_card.<locals>._complete5  s     m$K)9KfUmKr   rk         ?rP     )r  r         ?   rJ  r  )r   r   r   r   rS  rR  r   r`   rn   r  rv   r  r   r   r   r  r  rb   _card_fill_score)r;   r   r[  r   found_last4last4bestr  r   r|   show_btnro  s               r   _open_and_parse_cardr  (  s    ))I5XZXeXefK$/Ka TE2DL 8_ )	 V!45D
 <30671<V-f-JJsO$[%89
 LPK['.FGae#F!4$[%89 PTO_+D2JKeiHV9hx&89JJsO q 	A'{67J(KLIY|4*/	,'	*-=d-CC JJsO	 T?S)V T,'"\KU }} 	D	 ==  == s6   F3)GG+3GGG('G(+HHc                 ,     t         fddD              S )u~   Кол-во заполненных ключевых полей карты — для выбора лучшей попытки.c              3   F   K   | ]  }j                  |      sd   yw)r   N)rs   )r   r  rZ  s     r   r  z#_card_fill_score.<locals>.<genexpr>j  s     PS

3qPs   !!)rI  rK  rL  )sumr  s   `r   r  r  h  s    P<PPPr   c                    t        |       sg S g }t               d}d}t        |      |k  rt        |       }	 t	        |      }t        |      }t        d |D              }t        fd|D        d      }	|	>||k(  r|dz  }nd}|}|dk\  r	 |S | j                  d       t        j                  d       d}d}|	d	   }
j                  |
       t        | |	d
   |
      }|d   s|d   s
|d   s|d   r|
|d<   |j                  |       t!        |        t        j                  d       t        |      |k  r|S # t
        j                  $ r Y |S w xY w)u_  По порядку открывает каждую карту, доходит до реквизитов, нажимает Показать и парсит данные.

    Список карт — горизонтальная карусель. Карты вне экрана имеют bounds=[0,0][0,0],
    поэтому идём не по индексу, а по label с дедупликацией и горизонтальным скроллом,
    чтобы добраться до всех карт (в т.ч. когда их больше, чем помещается на экране).
    Nr   c              3   &   K   | ]	  }|d      ywr  r   r  s     r   r  z"parse_all_cards.<locals>.<genexpr>  s     :D$w-:s   c              3   2   K   | ]  }|d    vs|  ywr  r   )r   r  rW  s     r   r  z"parse_all_cards.<locals>.<genexpr>  s     Kgd1JtKs   r   rk   zinput swipe 600 392 150 392 500r  r[  r   rI  rJ  rK  rL  rM  )r  rQ  rv   r`   r   rn   r  r  r   nextrH   r   r   rU  r  rx   r   )r;   rG  rV  last_signaturestagnantrc   r|   rX  	signaturer
  r[  rZ  rW  s               @r   ra  ra  m  s{     '	G5DNH
g,
"'		 +D "$':E::	KKTR>N*A&N1}& N% LL:;JJsOw%ffX.>F- F<$8F8<LPVW\P]#(F< NN6"6

3I g,
"L NE }} 	B NE	s   D= =EEc                    | syg }t        | d      D ]*  \  }}|j                  d      xs d| }|j                  d      xs d}|j                  d      xs d}|j                  d	      xs d}|j                  d
      xs d}|j                  d      xs d}	|j                  d      xs d}
|j                  | d|        |j                  d|        |j                  d|        |j                  d|        |j                  d|        |j                  d|	        |j                  d|
        - dj                  |      S )uE   Формирует читаемый вывод списка карт.z[]r   )startrM  u   Карта rI  NonerJ  rK  rL  r  r  z. u      номер: z
   last4: u      срок: z   cvv: u      тип: u      вариант: rm   )	enumeraters   rx   rt   )rX  linesidxr  r[  r  r  rK  rL  r  variants              r   format_cards_outputr    sM   EuA. 6	T&=Ku*=-(2F&0&(#-vhhuo'HH[)3V	((>*4fuBug&'vh/0z%)*}VH-.xu%&{9+./*7)456" 99Ur   c                    ddddd}t        j                  d| t         j                        }|r"|j                  d      j	                         |d<   t        j                  d| t         j                        }|r6|j                  d      j                         j                  d	d
      xs d|d<   t        j                  d| t         j                        }|r6|j                  d      j                         j                  d	d
      xs d|d<   t        j                  d| t         j                        }|r|j                  d      |d<   |S )uX   Парсит оборот: расходы, доходы, месяц, категория.N)monthexpensesincomecategoryu   \b(?:Январь|Февраль|Март|Апрель|Май|Июнь|Июль|Август|Сентябрь|Октябрь|Ноябрь|Декабрь)\br   r   r  u$   Расходы\s*(\d[\d\s.,]*)\s*₽r   rj   rB   r  u"   Доходы\s*(\d[\d\s.,]*)\s*₽r  u   (?:Операции|Аналитика финансов|Нет карт|Выпустить карту|Перейти к аналитике финансов)r  )r   r   r   r   
capitalizerE   r6  )rh   r   month_matchexpenses_matchincome_matchcategory_matchs         r   parse_turnoverr    sS    	F ))  {  }A  IK  IV  IV  WK%++A.99;wYYFTVTaTabN+11!4::<DDS"MUQUz99BDPRP]P]^L'--a0668@@bIQTxYY     AE  MO  MZ  MZ  [N+11!4zMr   resource_idrh   content_desccontainsc                   | j                         D ]a  }|N|j                  j                  dd      xs d}||k(  s)|j                  d|z         s|j                  d|z         sT|dj	                  |j                  j                  d      xs dj                               }|r!|j                         |j                         vr#|j                         |j                         k7  r|dj	                  |j                  j                  d      xs dj                               }|r&|j                         |j                         vr9|c S |j                         |j                         k7  r`|c S  y)	ui  Найти первый узел в дампе по resource-id / text / content-desc.

    Совпадение по тексту/описанию — регистронезависимое. `contains=True` — подстрока.
    resource-id сопоставляется как полное значение или как суффикс ':id/<name>'.
    Nr)  rB   z:id//rj   rh   ri   )rq   rr   rs   endswithrt   ru   r   )	r|   r  rh   r  r  r~   ridr   cds	            r   
_find_noder    sA    		 "++//-4:C;&#,,v7K*LPSP\P\]`cn]nPoHHdkkoof5;BBDEE::<u{{}4$**,.#4;;??>:@bGGIJB%%'rxxz9  |1133'( r   c                    t        t        |             }t        |||||      }|y|t        |j                  j                  d            fS )ul   Свежий дамп + поиск узла. Возвращает (node, bounds_dict) либо (None, None).r  )NNr   )r   r`   r  r   rr   rs   )r;   r  rh   r  r  r|   r~   s          r   find_node_boundsr    sI    V,-Dd$\dlmD|dkkooh7888r   c                 r    t        t        |             }t        |d      }t        |d      }|duxr |duS )u   Экран входа: есть заголовок 'Введите номер телефона' и поле ввода телефона.u*   Введите номер телефонаrh   inputEditTextr  N)r   r`   r  )r;   r|   titlefields       r   is_on_login_screenr    s?    V,-Dt"NOEt9E2d!22r   r  c                    t        | |      \  }}||t        d|d       yt        | |d          t        j                  d       |j
                  j                  d      xs d}t        t        |      d	z   d
      }| j                  d       | j                  ddj                  dg|z        z          t        j                  d       y)ue   Фокус на поле ввода и удаление всего введённого текста.r  u   clear_text_field: поле u    не найденоFr         ?rh   rB   r  r   zinput keyevent 123input keyevent rj   67皙?T)r  r"   r   r   r   rr   rs   r   rv   rH   rt   )r;   r  r~   r   rN  counts         r   clear_text_fieldr  
  s    #FDLD&|v~)+8LMNVVH-.JJsOkkoof%+GGq "%E
LL%&
LL"SXXtfun%==>JJsOr   c                 H   t        j                  ddt        |            }t        d|dz         D ]  }t	        | |       t        | |      \  }}|$t        | |d          t        j                  d       |D ]+  }| j                  d|        t        j                  d       - t        j                  d	       t        | |      \  }}|4t        j                  dd|j                  j                  d
      xs d      nd}	|	|k(  r yt        d| d| d|	d|        y)u  Надёжно ввести цифры в поле: посимвольно + сверка с текстом поля, с повтором.

    `input text` на redroid иногда теряет символы, поэтому вводим по одному и
    проверяем итоговое значение, очищая и повторяя при расхождении.
    \DrB   r   r  r   r  input text gQ?333333?rh   Tztype_into_field(u   ): попытка u   : получено u   , ожидалось F)r   rT  r\   rR  r  r  r   r   r   rH   rr   rs   r"   )
r;   r  digitsr   attemptr~   r   chr   gots
             r   type_into_fieldr    s%    VVE2s6{+FHqL) B[9'KHfVVH%56JJsO 	BLL;rd+,JJt	 	

3"6{CaBFBRbffUB 7 =2>XZ&={m+=gYFYZ]Y``uv|u  A  	BB r   c                 *   t        t        |             }t        |dd      xs t        |d      }|yt        d       t	        | d	      \  }}|t	        | d
      \  }}|t        d       yt        | |d          t        j                  d       y)u   Если показан диалог 'Для правильной работы ... предоставьте' — нажать 'Отмена'.u(   Для правильной работыT)rh   r  permissions_missing_startr  FuV   Обнаружен диалог разрешений — нажимаю 'Отмена'u   Отменаr  button2uJ   dismiss_permission_dialog: кнопка 'Отмена' не найденаr   r  )r   r`   r  r"   r  r   r   r   )r;   r|   markerr~   r   s        r   dismiss_permission_dialogr  3  s    V,-D4HSWX 	Ed(CD  ~`a#F@LD&~'IFf~XYVVH-.JJsOr   c                    t        | d      \  }}|y|d   t        d|d   |d   z
  dz        z   }|d   d	   }	 | j                         }t        j                  t        j                  t        |                  j                  d
      }|j                  ||f      \  }}}	|	dkD  xr |dk  xr |	|z
  dkD  }t        d| d| d| d| d|	 d|rdnd        |S # t        $ r}
t        d|
        Y d}
~
yd}
~
ww xY w)u}  True/False — активна ли кнопка 'Получить новый код' (синяя vs серая с таймером).

    Возвращает None, если кнопки нет на экране. Определяем по цвету пикселя у левого
    края кнопки: активная ~ (0,91,255), неактивная ~ (245,247,250).
    getNewCodeButtonr  Nr   r   r      r   r   RGBu;   _get_new_code_button_enabled: screencap не удался:    r   P   zgetNewCode pixel@(,z)=(z) -> u   активнаu   неактивна)r  r   rM   r   openioBytesIOrN   convertgetpixelr5   r"   )r;   r~   r   r   r   rO   imagergbr?   is_blues               r   _get_new_code_button_enabledr  H  s$    $F8JKLD&~vR&/F6N"Bq!HIIAxA!

2::eDk23;;EB..!Q(1a #g2!c'2q1ulG
QCq3qc1#Qqc77GXl6mnoN  I#OPs   A'C 	C<$C77C<r-   c                    t        j                          |z   }t        j                          |k  rt        |       }|t        d       nO|rBt        | d      \  }}|;t        d       t	        | |d          t        j
                  d       yt        d       t        j
                  d       t        j                          |k  rt        d	       y
)u}   Ждёт, пока кнопка 'Получить новый код' станет активной, и нажимает её.uP   Кнопка 'Получить новый код' не найдена, жду...r  r  uS   Кнопка 'Получить новый код' активна — нажимаюr   r   TuU   Кнопка 'Получить новый код' ещё в таймере, жду...ud   Таймаут ожидания активации кнопки 'Получить новый код'F)r   r  r"   r  r   r   )r;   r-   r  stater~   r   s         r   wait_and_tap_get_new_coder  _  s    yy{W$H
))+
 ,V4=bc+F@RSLD&!ij )9:

3gh

3 ))+
  nor   codec                 R   t        j                  ddt        |            }t        | d      \  }}|t	        d       yt        | |d          t        j                  d       |D ]+  }| j                  d	|        t        j                  d
       - t        j                  d       y)u  Вводит 6-значный код в поле подтверждения.

    Поле кода — OTP-виджет: он не отдаёт введённый текст в атрибут `text`, а при
    верном коде Ozon сам уходит на экран пароля. Поэтому НЕ сверяем и НЕ чистим
    поле повторно — просто вводим цифры один раз, посимвольно.
    r  rB   r  r  uG   enter_flash_call_code: поле ввода кода не найденоFr   r  r  g333333?r  T)	r   rT  r\   r  r"   r   r   r   rH   )r;   r  r  r~   r   r  s         r   enter_flash_call_coder  t  s     VVE2s4y)F#FHLD&~UVVVH-.JJsO {2$'(

4 	JJsOr   c                    t        j                          |z   }t        j                          |k  rD	 t        t        |             ry	 t        j                  d       t        j                          |k  rDy# t        $ r Y 9w xY w)uz   Ждёт появления экрана пароля (Ozon сам перекидывает при верном коде).Tr   F)r   r  rd   r5   r   r;   r-   r  s      r   wait_for_lock_screenr!    sp    yy{W$H
))+
 	"=#89 : 	

3 ))+
    		s   A4 4	B ?B 
max_roundsc                     d}t        |      D ]<  }t        t        |             s |S t        | |      rd}t	        j
                  d       > |S )u  Вводит пароль на экране блокировки. При сценарии 'придумайте + повторите'
    код-пароль вводится дважды, поэтому повторяем ввод, пока экран пароля остаётся.FT      @)rR  r  rd   r%  r   r   )r;   r  r"  entered_anyr   s        r   enter_lock_password_repeatedr&    sY     K: "=#89  'vx8K

3 r   c                    	 t        |       }d}t        j                  d|t        j                        s&t        j                  d|t        j                        rd}n(t        j                  d|t        j                        rd}d}t        j                  d|      }|r.d	j                  |j                  d
      j                               }||y|xs d|dS # t        $ r Y yw xY w)u   Определяет экран ввода кода: тип доставки (звонок/СМС) и целевой номер.

    Возвращает {'method': 'call'|'sms'|'code', 'target': '+7 ...'} или None.
    Nu    последн\w*\s+6\s+цифрr   u   звонимcallu>   Отправили\s+код|Введите\s+код|СМС|SMSsmsz\+7[\s\-()0-9]{7,}rj   r   r  )r   r
  )rd   r5   r   r   r   rt   r   ru   )r;   dumpr   r
  r  s        r   detect_code_screenr+    s    
V$ F	yy4d"--PTVT]T]^mos{}  |I  |I  UJ	TVZbdbobo	pFII+T2E%++a...01~&.&&99  s   C 	C('C(c                     	 | j                  d      xs d}t        j                  d|      D ]  }|j	                  d      c S  t        j
                  d|      }|r|j	                  d      S dS # t        $ r Y yw xY w)u_   Возвращает package приложения на переднем плане (или '').zdumpsys windowrB   z'mCurrentFocus=Window\{[^}]*\s+([\w.]+)/r   zmFocusedApp=.*\s+([\w.]+)/)rH   r5   r   finditerr   r   r;   outr  s      r   get_foreground_packager0    s    ll+,2 GM {{1~II3S9E"5;;q>**  s   A/ /	A;:A;waitc                     t        |       t        k(  ry	 | j                  dt                t        j                  |       t        |       t        k(  S # t        $ r}t        d|        Y d}~Cd}~ww xY w)u  Гарантирует, что приложение Ozon на переднем плане.

    Если открыт лаунчер/другое приложение, экран Ozon прочитать нельзя, и проверка
    состояния входа ложно показывает «вход не выполнен». Поэтому поднимаем приложение.
    Tam start -n z)ensure_ozon_foreground: am start failed: N)r0  OZON_PACKAGErH   OZON_ACTIVITYr5   r"   r   r   )r;   r1  r?   s      r   ensure_ozon_foregroundr6    so     f%5?|M?34 	JJt!&)\99  ?7u=>>?s   A 	A5A00A5c                    t        |       }t        |       t        d      D ]  }	 t        |      }t        |      rdddc S t        j                  d|t        j                        rdd	dc S t        j                  d
|t        j                        rdddc S t        j                  d        dddS # t        $ r d}Y w xY w)u  Проверяет текущий экран устройства и определяет, выполнен ли вход в ЛК.

    Вход считается выполненным, если открыт экран ввода код-пароля (PIN) либо
    главный экран приложения. Возвращает {'logged_in': bool, 'screen': str}.

    Перед чтением экрана поднимаем приложение Ozon на передний план: если оно
    свёрнуто (открыт лаунчер/другое приложение), экран прочитать нельзя и вход
    ложно определялся как невыполненный.
    rR   r+   rB   Tpin)	logged_inscreenu   \bГлавная\b|Основной\s+сч[её]т|Баланс|Остаток|Доходы|Расходы|Операции|Оплатить|Пополнить|Перевестиr   mainu   Введите\s+номер\s+телефона|Введите\s+код|последн\w*\s+6\s+цифр|Войти\s+по\s+почтеFloginr   unknown)r@   r6  rR  rd   r5   r  r   r   r   r   r   )r#   r;   r   r*  s       r   check_login_stater>    s     5F6"1X 	 (D t$!%7799 B--

 "&8899 V--

 "'':: 	

314 )44/  	D	s   B::CCnew_code_timeoutpress_get_new_codec                    |d }t        |       }t        |      st        d      t        d       t	        |d       t        j                  dd	t        |            }t        |      d
k(  r|d   dv r|dd }t        d|        t        |d|      st        d|       |j                  d       t        j                  d       t        |d      \  }}	|	t        |d      \  }}	|	t        d      t        ||	d          t        j                  d       t        |       t        j                  d       |r$t!        ||      st        d      t        |       nt        d       t#        |      }
t        d|
        |
|d}	  ||      }t        j                  dd	t        |            }t        |      dk7  rt        d|      t        d        t'        ||      st        d!      t)        |d"      st        d#      t        d$       t+        ||      st        d%      t-        | |       t/        | |       t        d&|  d'| d(       t1        d)|  d*|  d+       y,# t$        $ r
  |       }Y w xY w)-ug  Добавить (залогинить) ЛК в приложении Ozon по номеру телефона и паролю.

    Шаги:
      1) проверка, что открыт экран входа (заголовок + поле телефона);
      2) очистка поля ввода;
      3) ввод номера без +7 (например 9000000000);
      4) нажатие 'Войти' (+ закрытие диалога разрешений через 'Отмена');
      5) ожидание активации 'Получить новый код' и нажатие;
      6) запрос 6-значного кода у пользователя (code_provider);
      7) ввод кода;
      8) проверка перехода на экран пароля и ввод пароля существующей функцией;
      9) сохранение номера/пароля в БД и отчёт с предложением полного чека.

    `code_provider` — callable без аргументов, возвращающий код (по умолчанию input()).
    Nc                  4    t        d      j                         S )NuT   Введите 6-значный код из входящего звонка/СМС: )inputrE   r   r   r   code_providerz!add_device.<locals>.code_provider  s    opvvxxr   rR   u   Сейчас открыт не экран входа: нет поля телефона или заголовка 'Введите номер телефона'u,   Экран входа подтверждёнr  r  r  rB      r   )r   r   r   u(   Ввожу номер телефона: uP   Не удалось корректно ввести номер телефона zinput keyevent 111r  submitButtonu
   Войтиr  u-   Не найдена кнопка 'Войти'r         @r  r,   u   Кнопка 'Получить новый код' не стала активной за отведённое время (возможно, сработал лимит повторной отправки — попробуйте позже)ux   Пропускаю 'Получить новый код' — использую код из первой отправкиu   Экран кода: )r	  r;   r  u;   Ожидался код из 6 цифр, получено: u!   Код получен, ввожуu'   Не удалось ввести код      9@uz   После ввода кода не появился экран пароля — вероятно, код неверныйuF   Экран пароля обнаружен — ввожу парольuT   Не удалось ввести пароль на экране блокировкиu   ЛК добавлен для 'u   ' (номер z).u   ЛК 'ul   ' успешно добавлен. Рекомендую выполнить полный чек: full_check('z').T)r@   r  r3   r"   r  r   rT  r\   rv   r  rH   r   r   r  r   r  r  r+  rF   r  r!  r&  update_numberupdate_passwordr    )r#   r  r  rD  r?  r@  r;   r  r~   r   	code_hintcode_contextraw_coder  s                 r   
add_devicerN     s     	y 5F f% l
 	
 67 V9 VVE2s6{+F
6{bVAY*4
26(;<6?F;mntmuvww LL%&JJsO#FGLD&~'\Bf~JKKVVH-.JJsO f%JJsO (9IJJ  	"&)  G  	H #6*I
	{+,%8L# . 66%S]+D
4yA~XY]X`abb+, !.DEE  5  X  Y  	YPQ'9qrr +v&K*
(^F82NO	
 TT_S``c	e 7  # ?#s   I) )I<;I<c                 <   d }d }ddddg d}t        |       }	 t        |      }t        |      rct	        d       t        |       }|s
t               }t	        d|rd	nd        t        ||      }t	        d
|        t        j                  d       	 t        |      }t        |      }	|	j                  d      |d<   |	j                  d      |d<   t        | |      |d<   |d   xs d}
|
r |
j                  dd      j                         nd}|rt	        d| d       t        j                  d       t        ||       	 t        |      }t!        |      }|j                  d      r|j                  d      |d<   |j                  d      |d<    ||       t        j                  d       t        |d      rNt        j                  d       	 t        |      }t#        |      }||d<    ||       t        j                  d       t        |d      r-t        j                  d       t%        |      }||d<    ||       t'        d       t'        d|j                  d              t'        d|j                  d              t'        d|j                  d              t'        d|j                  d              t'        d       t'        t)        |j                  dg                    d  }	  ||j                  dg             }|j                  d      |j                  d      |j                  d      |j                  d      d!   |j                  d      d"   |d#}|j                  d      |j                  d      rd$nd%|d<   t+        | |       t	        d&|  d'|        |S # t        $ r d}Y w xY w# t        $ r d}Y -w xY w# t        $ r d}Y w xY w# t        $ r d}Y w xY w# t        $ r}t	        d(|  d)|        Y d}~|S d}~ww xY w)*u  Выполнить полный чек по шагам:
    1) подключиться к устройству по имени
    2) если экран блокировки — ввести пароль
    3) определить текущий экран (главная/операции/аккаунт/основной счет)
    4) перейти на Главная (нажимая кнопку Назад при необходимости)
    5) проверить баланс и имя; нажать по имени -> перейти в Аккаунт
    6) в Аккаунт: прочитать номер и имя, затем нажать Назад
    7) найти и нажать 'Все' в разделе операций
    8) прочитать оборот
    9) Назад
    10) открыть Основной счёт и прочитать все карты
    11) Назад

    Возвращает словарь с результатами.
    c                 `   	 t        |       }t        j                  d|t        j                        rd|fS t        j                  d|t        j                        rd|fS t        |      xs t        |      j                  d      }|rd|fS t        |       rd	|fS d
|fS # t        $ r Y yw xY w)N)r=  rB   uN   \bГлавная\b|Основной\s+сч[её]т|Баланс|Остатокr   r=  uP   Доходы|Расходы|Операции|Последние операцииu   операцииr  r>  u   основной счетr=  )	rd   r5   r   r   r   r  r  rs   r  )r;   r*  nums      r   detect_screenz!full_check.<locals>.detect_screeny  s    	! (D
 99fhltv  uB  uB  C#T))99hjnvx  wD  wD  E%t++ &[*G*M*Q*QRZ*[#T))'.44$#  	! 	!s   B! !	B-,B-c                 J   	 t        |       }t        |      }t        |d      }|rNt        |d   t        t
        f      rt        | g|d     nt        | |d          t        j                  d       y	 t        |        t        j                  d       y# t        $ r Y ,w xY wNu#   ^\s*(Назад|Back|‹|←|<)\s*$r   r  Tr`   r   r  r   r   r   r   r   r   r5   r   r;   rc   r|   btns       r   tap_backzfull_check.<locals>.tap_back      	#F+I +D&t-STCc(meT];$V<c(m<$VS];

3  	6

3	  		   A1B 	B"!B"N)r|  r{  account_numberturnoverrX  rR   rB   *   lock screen detected — attempting unlockusing password: ***unlock result:       @r{  r|  rm  r$  z"full_check: tapping account name ''r  r  r[  r     Всеr\     Основной счётrX  z=== Full check result ===zAccount name: z	Balance: zAccount number: z
Turnover: zCards:c                    g }| xs g D ]m  }|j                  d      xs d}|s|j                  d      xs dj                  dd      }|j                  d      xs d}|j                  | d| d|        o dj                  |      S uB  Serialize list of card dicts into the required string format.

        Each card is stored as: full_number/expiry(without "/")/cvv
        Multiple cards are separated by ':'
        Карты без номера пропускаем, чтобы не появлялись пустые записи вида '//'.
        rI  rB   rK  r  rL  r*   rs   r6  rx   rt   
cards_listr/  crQ  rK  rL  s         r   serialize_cardsz#full_check.<locals>.serialize_cards       " 	0A%%&,"CeeHo+44S"=F%%,$"CJJ#axq./	0 xx}r   r  r  )namer|  r  r  outcomerX  r   r   zDatabase updated for z: cards=zFailed updating DB for rD   )r@   rd   r5   r  r"   get_passwordr   r%  r   r   r~  rs   ry  r6  rE   r   r  r  ra  r    r  update_device)r#   rR  rX  rV  r;   r*  r   	ok_unlock	main_dumpaccount_balance_infor{  sanitized_name	acct_dumpaccount_number_infoops_dumpturnover_inforX  rk  cards_serializedupdate_payloadr?   s                        r   
full_checkr{  h  s   ",( G 5FV$ 4 89;'02Cu678/<	oi[)*

3!&)	 :)D266~FGN-11)<GI*;	BGI >*0bL>J\))#r288:PRN00@BC

37	%f-I <IF"">2&9&=&=n&MGN#$7$;$;H$E !

3 vy1

3	$V,H 'x0+


3 v'CD

3' 	
%&	N7;;~67
89	Igkk),-
./	W[[)9:;
<=	Jw{{:./
01	(O	
gkk'26
78"<*7;;w+CD KK/{{9-kk"23kk*-h7{{:.z:%
 ;;y!--4[[-CN9%k>2#K=9I8JKL N]  "  	&  	I	   	H	n  <%k]"SE:;;N<s`   N. O  O O$ 4B8O6 .N=<N= OOO! O!$O32O36	P?PPc                 .   	 t        |       }t        |      s|S t        d       t	        |      xs
 t               }t        | |      }t        d|        t        j                  d       	 t        |       S # t        $ r d}Y ww xY w# t        $ r Y yw xY w)NrB   r]  r`  r$  )	rd   r5   r  r"   ro  r   r%  r   r   )r;   r#   r*  r   rq  s        r   _unlock_if_neededr}  !  s    V$ t$45
{
#
G'E'GC+FC8I/)%&JJsOV$$    s#   A7 ,
B 7BB	BBrm  c                    t        j                  d| xs dj                  dd      j                  dd      j                               D cg c]  }|s|	 }}|syt	        |      dk(  rt        j
                  |d         S t        j
                  |d         }|d   }| dt        j
                  |       d	t        j
                  |d          d
S c c}w )NrO  rB   r$  rs  rj   r   r   z\s+(|z\.?))r   ru   r6  rE   rv   escape)rm  ppartsfirstrests        r   _lk_name_patternr  3  s    $*")=)=c2)F)N)NvWZ)[)a)a)cdj1hiQjEj
5zQyyq""IIeAhE8DgT"))D/*!BIId1g,>+?tDD ks   CCdb_namec                 @   g }t        | xs d      }|r|j                  t        |             t        j                  d| xs d      D ]+  }|j                  t        |j                  d                   - |rh|j                  t        |             |j                  dd      j                         xs dgd   }|r$|j                  t        j                  |             |j                  d       t        j                  d |D              D cg c]  }| c}S c c}w )NrB   u)   [А-ЯЁ][а-яё]+[ \t\xa0]+[А-ЯЁ]\.?r   rs  rj   u"   [А-ЯЁ][а-яё]+\s+[А-ЯЁ]\.?c              3   &   K   | ]	  }|s|  y wr   r   )r   r  s     r   r  z(_lk_name_tap_patterns.<locals>.<genexpr>L  s     $>1AQ$>s   )rq  rx   r  r   r-  r   r6  ru   r  ry   rz   )r   r  rp  screen_namer  r  r  s          r   _lk_name_tap_patternsr  ?  s    H,Y_"=K(56I9?XZ[ :(Q89:(12-335="qAOOBIIe,-OO9:}}$>$>>?!A???s   	Dswipesc                     t        d| d       t        |      D ])  }	 | j                  d       t	        j
                  d       + y# t        $ r}t        d|        Y d}~ yd}~ww xY w)uF   Долистать текущий экран вниз до конца.zscroll_screen_to_bottom: r    input swipe 360 1180 360 220 350z'scroll_screen_to_bottom: swipe failed: Nr  )r"   rR  rH   r5   r   r   )r;   r  ir?   s       r   scroll_screen_to_bottomr  O  sk    
#F87346] 	LL;< 	

3  	9#?@	s   A	A*A%%A*
max_swipesc           
         t        |t              r|g}g }|D ]\  }|r"|j                  d|j                         f       '|j                  dt	        j
                  |t        j                        f       ^ t        |dz         D ]7  }t        |       }t        |      }|j                         D ]  }	dD ]  }
|	j                  j                  |
      }|s!dj                  |j                               }|sCd}|j                         }|D ]'  \  }}|dk(  r||k(  }n|j                  |      du}|s' n |st!        t#        |	j                  j                  d	                  }|st%        | g|     y
  ||k\  r yt'        d|d|dz           	 | j)                  d       t-        j.                  d       : y# t*        $ r}t'        d|        Y d}~5d}~ww xY w)uq   Листает вниз, пока не найдёт один из элементов, и нажимает его.r   r   r   r   rg   rj   FNr   Tzscroll_and_tap: u$    не на экране, свайп r  zscroll_and_tap: swipe failed: gffffff?)r   r\   rx   r   r   compiler   rR  r`   r   rq   rr   rs   rt   ru   r   r   r   r   r"   rH   r5   r   r   )r;   text_patternsr  r   compiledr  r  rc   r|   r~   r   r   rh   matchedr2  kindspecr   r?   s                      r   scroll_and_tapr  [  s   -%&H  NOOWgmmo67OOT2::gR]]#KLM	N a( "'	Y'IIK 	D0 -xx.jjl"* JD$w"%+"&++d"34"? ,\$++//(:S-TU	  4)4-	0 j   	}//ST[^_T_S`ab	8LL;< 	

3E"F   	80677	8s   G	G"
GG"c                 8    t        | dddddddddddddd       y)uo   Сбросить привязку ЛК в БД — панель покажет экран добавления.rB   Nr   )r  r  rm  r|  r  rn  rX  
card_flagsrm  
blocked_attg_id	leased_atlease_price)rp  rR   s    r   clear_lk_sessionr    s8    +  r   c                 h   t        |       }t        ||       }t        |      rt        d|         t	        |        yt        j                  d|xs dt
        j                        s-t        |d       t        j                  d       	 t        |      }	 t        |      }t        |t        |       xs d      }t        d	|       d
}|D ]  }t        ||      sd} n |st        d      t        j                  d       t        d       t!        |d       t        j                  d       t#        |g ddd      }|st        d      t        j                  d       t        d       t#        |ddgdd      st        |d       t        j                  d       t        j                         dz   }t        j                         |k  r	 t        |      }t        j                  d|t
        j                        r&t#        |dgdd       t        j                  d       pt        j                  d|t
        j                        s&t        j                  d|t
        j                        r[t        d       t#        |g ddd      xs t        |d       }|rt        j                  d!       t        d"|         t	        |        yt        |      rt        d#|         t	        |        yt        j                  d$|t
        j                        r(t#        |g d%dd       t        j                  d&       t        j                  d!       t        j                         |k  rt        d'      # t        $ r d}Y w xY w# t        $ r
 |xs d}Y w xY w# t        $ r d}Y w xY w)(u   Выйти из ЛК: имя -> скролл до «Выйти» -> проверка экрана входа -> сброс ЛК в панели.rR   uK   logout_lk: уже экран входа — сбрасываю ЛК для Tu2   \bГлавная\b|Основной\s+сч[её]тrB   r   u   ^\s*Главнаяg333333?z$logout_lk: tapping LK name patterns=Fu1   Не удалось нажать на имя ЛКr   z&logout_lk: scrolling profile to bottomr+   )r  r  )    Выйти из аккаунтаu   Выйти из профиля
   Выйтиr  r   r  u7   Не найдена кнопка «Выйти» в ЛКu.   logout_lk: tapping «Не в этот раз»u   Не в этот разu   Не в этот раз.rk         4@u   не в этот разr   uw   войти\s+(ли\s+)?в\s+эт(от|ом)\s+аккаунт|продолжить\s+как|это ваш аккаунтu   выбрать другойuh   logout_lk: экран повторного входа — нажимаю «Выбрать другой»)   Выбрать другой*   Выбрать другой аккаунт   Другой аккаунтr  r  u,   logout_lk: выход успешен для u?   logout_lk: экран входа подтверждён для uB   выйти из (аккаунта|профиля)|подтверд)r  r  u   Подтвердитьr  uC   После выхода не открылся экран входа)r@   r}  r  r"   r  r   r   r   r   r   r   rd   r5   r  get_namer3   r  r  )	r#   r;   r*  rp  tappedname_patternlogout_tappedr  tapped_others	            r   	logout_lkr    sN   5FV[1D&!YZeYfgh%99JDJTV^`^k^kl(=>

3	 (DV$ %T8K+@+FBGH
.xl;<F  "6<8F NOOJJsO01F1-JJsO"\	M TUUJJsO89&#<>X"Yaerst(BCJJsOyy{T!H
))+
 	 (D 99/R]]K6$=#>dWXYJJsO99 G--
 YY5t2==Qz{ A 	 S +63QR  

3>{mLM[)f%QR]Q^_`[)99Z\`hjhuhuv6#ow{  IJ  KJJsO

3S ))+
 V \
]]e  	D	
  zrJ  	D	s6   
M: N N" :N	N	NN"N10N1max_backc                    t        |       }t        |dz         D ]  }t        |      rt        d|          y	 t	        |      }t        j                  d|t        j                        rBt        d       t        |g d	dd
      xs t        |d      }|rt        j                  d       ||k  st        |       t        j                  d        t        |      S # t
        $ r d}Y w xY w)u`  Отмена входа: жмём «Назад», пока не окажемся на экране входа.

    Если по пути всплывает предложение войти в существующий аккаунт
    («Войти в этот аккаунт?» / «Продолжить как …»), выбираем «Выбрать другой
    аккаунт», чтобы вернуться именно на экран ввода номера, а не залогиниться.
    Возвращает True, если удалось выйти на экран входа.
    rR   r   u>   cancel_login: экран входа достигнут для TrB   u   войти\s+(ли\s+)?в\s+эт(от|ом)\s+аккаунт|продолжить\s+как|это ваш аккаунт|выбрать другойr   u{   cancel_login: предложение войти в аккаунт — жму «Выбрать другой аккаунт»)r  r  r  rk   r  r  ffffff?)r@   rR  r  r"   rd   r5   r   r   r   r  r   r   r   r   )r#   r  r;   r  r*  r  s         r   cancel_loginr    s    5FA& f%PQ\P]^_	 (D 99 c--

   N  O A 	 S +63QR  

3XvJJsO?B f%%5  	D	s   C  C.-C.c                    t        |       }	 t        |      }t        |      rct	        d       t        |       }|s
t               }t	        d|rdnd         t        ||      }t	        d|        t        j                  d       	 t        |      }t        |      }t        | |j                  d             t        | |       y # t        $ r d}Y w xY w# t        $ r d}Y Qw xY w)	NrR   rB   r]  r^  r_  r`  ra  r|  )r@   rd   r5   r  r"   ro  r   r%  r   r   r~  update_balancers   ry  )r#   r;   r*  r   rq  rr  rs  s          r   check_balancer  1  s    5FV$ 4 89;'02Cu678/<	oi[)*

3!&)	 :)D; 4 8 8 CDk9--  "  	s#   C C CCC%$C%c                 t   t        |       }	 t        |      }t        |      rct	        d       t        |       }|s
t               }t	        d|rdnd         t        ||      }t	        d|        t        j                  d       d }t        |d	      rt        j                  d
       	 t        |      }t        |      }t        | |j                  d             t        | |j                  d              ||       t        j                  d
       y y # t        $ r d}Y w xY w# t        $ r d}Y w xY w)NrR   rB   r]  r^  r_  r`  ra  c                 J   	 t        |       }t        |      }t        |d      }|rNt        |d   t        t
        f      rt        | g|d     nt        | |d          t        j                  d       y	 t        |        t        j                  d       y# t        $ r Y ,w xY wrT  rU  rV  s       r   rX  z check_turnover.<locals>.tap_backb  rY  rZ  rc  r  r  r  )r@   rd   r5   r  r"   ro  r   r%  r   r   r   r  update_incomers   update_outcome)r#   r;   r*  r   rq  rX  rw  rx  s           r   check_turnoverr  P  s$   5FV$ 4 89;'02Cu678/<	oi[)*

3, vy1

3	$V,H 'x0k=#4#4X#>?{M$5$5j$AB

3 2G  N  	H	s#   D ,D) D&%D&)D76D7c                    t        |       }	 t        |      }t        |      rct	        d       t        |       }|s
t               }t	        d|rdnd         t        ||      }t	        d|        t        j                  d       d }d	 }t        |d
      rHt        j                  d       t        |      }t        |        ||      } ||       t        | |       y y # t        $ r d}Y w xY w)NrR   rB   r]  r^  r_  r`  ra  c                 J   	 t        |       }t        |      }t        |d      }|rNt        |d   t        t
        f      rt        | g|d     nt        | |d          t        j                  d       y	 t        |        t        j                  d       y# t        $ r Y ,w xY wrT  rU  rV  s       r   rX  zcheck_cards.<locals>.tap_back  s    '/	$Y/*41WX!#h-%?(@#h-@(X?JJsO  vJJsO	  rZ  c                    g }| xs g D ]m  }|j                  d      xs d}|s|j                  d      xs dj                  dd      }|j                  d      xs d}|j                  | d| d|        o dj                  |      S rf  rg  rh  s         r   rk  z$check_cards.<locals>.serialize_cards  rl  r   rd  r  )r@   rd   r5   r  r"   ro  r   r%  r   r   r   ra  r    update_cards)	r#   r;   r*  r   rq  rX  rk  rX  ry  s	            r   check_cardsr    s    5FV$ 4 89;'02Cu678/<	oi[)*

3&( v'CD

3'e*51["23 Ei  s   C" "C0/C0r  marginc                 ,   	 t        t        |             }d}|j                         D ]<  }t	        |j
                  j                  d            }|s*t        ||d   |d         }> |j                         D ]  }dD ]  }|j
                  j                  |      xs d}dj                  |j                               }	|	r|	j                  d	      rVt        j                  ||	t        j                  
      s}t	        |j
                  j                  d            }|s|d   |d   z   dz  }
t        |d   |d         }t        |d   |d         }||z   dz  }|r
||k\  r||z
  }|
dk  s|dk  rt        | |
|         y  y# t        $ r Y yw xY w)u!  Тапает по элементу с текстом/description, зажимая точку внутри экрана.

    Нужно для нижних кнопок-CTA («Заказать карту», «Выпустить», «Отлично»),
    у которых uiautomator иногда отдаёт кривые bounds (bottom < top, либо центр
    ниже видимой части экрана). В таких случаях обычный тап по top_center
    промахивается мимо кнопки.
    Fr   r   r   r   rg   rB   rj   rl   r   r   r   rk   T)r   r`   r5   rq   r   rr   rs   r   rt   ru   rw   r   r   r   minr   )r;   r  r  r|   r   r~   r  r   r   rh   cxr   r   cys                 r   tap_text_clampedr    s   [01 F		 8238ah7F8
 		 , 	DKKOOD)/RE88EKKM*D4??:699Wd"--@T[[__X67AF)aj(Q.Bah(,C51X;/F,1$B",f_Qw"'VR,'	* =  s   F 	FFc                    g }| xs g D ]m  }|j                  d      xs d}|s|j                  d      xs dj                  dd      }|j                  d      xs d}|j                  | d| d|        o dj                  |      S )u  Сериализует список карт в строку для БД: full_number/expiry(без «/»)/cvv, карты через ':'.

    Карты без номера пропускаем, чтобы не появлялись пустые записи вида '//'.
    rI  rB   rK  r  rL  r*   rg  rh  s         r   _serialize_cards_for_dbr    s    
 CB ,eeM"(b%%/'R00b9eeEl b

cU!F81SE*+, 88C=r   r[  c                     t        j                  d| xs d      }|r|j                  d      S t        j                  d| xs d      }|r|j                  d      S d S )Nz(\d{4})\s*$rB   r   z(\d{4}))r   r   r   )r[  r  s     r   _card_last4_from_labelr  	  sP    IInekr2E{{1~IIj%+2.E"5;;q>,,r   
serializedc                 (   t               }t        | xs d      j                  d      D ]f  }t        j                  dd|r|j                  d      d   nd      }|s3|j                  |       t        |      dk\  sS|j                  |dd         h |S )NrB   r*   r  r  r   r  r  )rQ  r\   ru   r   rT  rU  rv   )r  r1  chunkrQ  s       r   _known_card_keysr  	  s    5DZ%2&,,S1 ffUBS!1!!42Gs8q=HHSX Kr   existingrZ  c                 
   t        |g      }|s| xs dS t        j                  dd|j                  d      xs d      }t	        | xs d      j                  d      D cg c]  }|j                         s| }}g }d}|D ]W  }t        j                  dd|j                  d      d         }	|r|	|k(  r|j                  |       d}G|j                  |       Y |s|j                  d|       dj                  |      S c c}w )	u   Добавляет/заменяет карту в сериализованной строке БД. Новая карта — первой.rB   r  rI  r*   Fr  r   T)
r  r   rT  rs   r\   ru   rE   rx   insertrt   )
r  rZ  piecerQ  r  r  r/  replacedpartpart_nums
             r   _merge_card_into_serializedr  	  s    #VH-E~2
&&FJJ}5;
<CHN+11#6D1!'')QDED
CH 66%TZZ_Q%788s?JJuHJJt 

1e88C= Es   D 5D c                    |xs
 t               }t        j                         dz   }t        j                         |k  r	 t        |       }t        |      }t        |      }d}|D ]  }t        |d         }|s||vs|} n ||r|d   }t        |d      }	|rt        | |d   |d         }
n)|	rt        | |	d   d      }
nt        j
                  d       |
j                  d	      s3|
j                  d
      s"|
j                  d      s|
j                  d      r|
S t        j
                  d       t        j                         |k  ry# t        $ r t        j
                  d       Y Fw xY w)u   После выпуска открывает новую карту, жмёт «Показать» и парсит реквизиты.r  r  Nr[  r   rP  r   newrI  rJ  rK  rL  )rQ  r   r`   r   r5   r   r  r  r  r  rs   )r;   
known_keysr  rc   r|   r  r
  r  r  r  rZ  s              r   _parse_issued_cardr  -	  sW   $suJyy{T!H
))+
 	#F+I +D
 $D) 	D*4=9Ej0		
 >gQZF'.FG)&&2BF7OTF)&(82DeLFJJsO::m$

<(@FJJxDX\b\f\fgl\mM

3; ))+
 < 5  	JJsO	s   E E-,E-intervalc                 F   t        j                          |z   }t        j                          |k  rb	 t        |       }|r't        j                  ||t        j
                        ryt        j                  |       t        j                          |k  rby# t        $ r d}Y dw xY w)u   Ждёт, пока в дампе экрана появится текст по паттерну. True — если появился до таймаута.rB   r   TF)r   rd   r5   r   r   r   r   )r;   r  r-   r  r  rh   s         r   wait_for_text_on_screenr  R	  s    yy{W$H
))+
 	 (D BIIgt2==A

8 ))+
    	D	s   B B B 	card_kinddesign	update_dbc                    t        |       }dt        dt        fd}	 t        |      }t        |      rct        d       t        |       }|s
t               }t        d|rdnd	        t        ||      }t        d
|        t        j                  d       d }	t        |d      s	 |dd      S t        j                  d       t        |dd      s	 |dd      S t        j                  d       t        d      D ]w  }
t        |ddd      r nft        |ddd      r&|j                  d       t        j                  d       t!        |d      st!        |d      rt        j                  d       w n t        |dd       s	 |dd!      S t        |d"t#        j$                  |       d#      s,t        |t#        j$                  |            s |dd$| d%      S t        j                  d       t        |d&d'       rgt        |d"t#        j$                  |       d#      s.t        |t#        j$                  |            st        d(| d)       t        j                  d       nt        d*       t        |d+d'       s	 |dd,      S t!        |d-      st!        |d+      s	 |dd.      S t        |d/d0d      s	 |dd1      S t        d2       t        j                  d       t!        |d3      xs t!        |d4       t        j                  d       t'        |rt)        |       nd      }t+        ||      }d	}|rJ	 t)        |       xs d}|r't-        ||      }t/        | |       t        d5|        n|xs d	}t        d6        |	|        |	|        |dd8||9      S # t        $ r d}Y w xY w# t        $ r}t        d7|        Y d	}~Jd	}~ww xY w):uD  Заказывает новую карту Ozon Банка на устройстве.

    Проходит весь сценарий выпуска: Основной счёт → Заказать карту →
    (промо-экран) → выбор типа карты → выбор дизайна → Выпустить → экран
    «Карта готова» → читает реквизиты новой карты → пишет в БД → два раза
    «Назад» на главный экран. Возвращает dict со статусом.
    rR   successmessagec                 ,    t        d|        | |d|S )Nz
add_card: )r  r  )r"   )r  r  extras      r   r   zadd_card.<locals>.resultj	  s!    j	"#"w@%@@r   rB   r]  r^  r_  Nr`  ra  c                 J   	 t        |       }t        |      }t        |d      }|rNt        |d   t        t
        f      rt        | g|d     nt        | |d          t        j                  d       y	 t        |        t        j                  d       y# t        $ r Y ,w xY wrT  rU  rV  s       r   rX  zadd_card.<locals>.tap_back}	  rY  rZ  rd  FuP   не найден «Основной счёт» на главном экранеr  u   Заказать картуT)r   u@   не найдена кнопка «Заказать карту»r   r  u&   Выберите\s+тип\s+картыrG  r  )r-   r  u9   Закажите\s+карту|Заказать картуr  zinput swipe 360 900 360 600 400u   ^Заказать карту$r  r,   uA   не появился экран выбора типа карты^$u&   не найден тип карты «   »u   Выберите\s+дизайн       @u   add_card: дизайн «uK   » не найден, пробуем продолжить с текущимu}   add_card: экран выбора дизайна не появился — возможно, дизайн уже выбранu   Выпуститьu;   не появилась кнопка «Выпустить»u   ^Выпустить$u7   не удалось нажать «Выпустить»u(   карта\s+готова|Отличноg      D@uL   не дождались подтверждения выпуска картыu4   add_card: карта успешно выпущенаu   ^Отлично$u   Отличноu1   add_card: карты обновлены в БД: uY   add_card: не удалось прочитать реквизиты новой картыuC   add_card: не удалось обновить карты в БД: u   карта выпущена)rX  r  )r@   boolr\   rd   r5   r  r"   ro  r   r%  r   r   r   rR  r  rH   r  r   r  r  	get_cardsr  r  r  )r#   r  r  r  r;   r   r*  r   rq  rX  r   knownrZ  ry  r  r?   s                   r   add_cardr  `	  s    5FA As AV$ 4 89;'02Cu678/<	oi[)*

3( #6+GHeoppJJsO #6+HPTUe_``JJsO 1X 	"6+T^alop"6+gqt  @C  DLL:;JJsOF$DEIYZ`  cA  JBJJsO	 #6+T^abe`aa #6a		)0D/EQ+GH&vryy/CD%#I)TV!WXXJJsO v'ISVW&v!BIIf4E3Fa/HI*6299V3DE/x  8C  D  E

3  L  	M #6+@#NeZ[[F$;<(=>%!Z[[ #6+V`dorsekll>? 	JJsOV01`5EfN_5`JJsO yY{3bIE.F
	] -3H#>x#P [*:;GHXGYZ[#+#3t op
 VV$5=MTZ[[g  X  	]UVYUZ[\\	]s*   N 8A	N/ N,+N,/	O8OO)
zcd ~/redroid-proxydocker compose downzdocker compose up -d --buildzsleep 5z5docker exec redroid setprop service.adb.tcp.port 4567z,docker exec redroid setprop ctl.restart adbdzsleep 3z0docker exec redroid getprop service.adb.tcp.portz)docker exec redroid getprop init.svc.adbdzsleep 10r   rG  c           	      6   t        |       }t        |       }|r|dv ry	 t        |      }t        ||      }	 |j                  ||       t        d| d|        y# t        t        f$ r Y yw xY w# t        $ r}t        d| d| d|        Y d}~yd}~ww xY w)ug   Сбросить ADB-подключение к устройству, если оно ещё висит.)NrB   Nr'   zADB disconnect r*   rD   )	r1   r2   r4   rF   rG   r0   remote_disconnectr"   r5   )r#   r$   r%   r(   r)   r<   r?   s          r   disconnect_redroidr  	  s    +DK D4:%4y H84F4  t,odV1TF+, z"   4odV1TF"SE2334s(   A #A1 A.-A.1	B:BBdelayc           
      T   d}t        d|dz         D ]F  }t                t        |        	 t        |       }|j	                  d       t        d| d       |c S  t        d	|       # t        $ r5}|}t        d| d| d|        t        j                  |       Y d}~d}~ww xY w)
uY   Подключиться по ADB после перезапуска контейнера.Nr   rC   u'   reboot: ADB готов (попытка r   u   reboot: ждём ADB r  rD   u7   Не удалось подключиться по ADB: )
rR  r   r  r@   rH   r"   r5   r   r   r3   )r#   r   r  last_excr  r;   r?   s          r   wait_for_adbr  
  s    HHqL)  ;'	$[1FLL#9'!DEM PQYPZ[
\\	  	H'y(2cUCDJJu	s   ,A))	B'2+B""B'rV  c                 p   | xs g D ]  }|j                  d      xs dj                         }|j                  d      }|j                  d      xs d}|j                  d      rd| c S |dv ri|dk(  rt        d	| d
       ~|j                         rd|j                          nd}d| d| | c S  y)NcommandrB   	exit_codestdoutskippedu;   SSH-сессия оборвалась до команды: )r   Nr  u)   reboot: docker compose down вернул u   , продолжаемrm   u)   Команда не удалась (exit z): )rs   rE   r"   )rV  rI   r  r  r  r  s         r   _reboot_ssh_errorr  
  s    2 U88I&,"335xx$(#)r88IPQXPYZZ9++;D6AWXY)/"V\\^$%R:4&G9UGTTU r   u   ozon\s*банкzozon\s*bankc           	      h   d}t        d|dz         D ]o  }t                	 | j                  d      xs dj                         }|dk(  rt        d| d        y t        d| d| d	|       t        j                  |       q t        d
|d      # t        $ r}t        |      }Y d }~id }~ww xY w)NrB   r   zgetprop sys.boot_completedr   u)   reboot: boot_completed=1 (попытка r   u*   reboot: ждём загрузку Android r  z: boot_completed=u2   Android не загрузился (boot_completed=)
rR  r   rH   rE   r5   r\   r"   r   r   r3   )r;   r   r  lastr  r?   s         r   _wait_boot_completedr  1
  s    DHqL) 
 	LL!=>D"KKMD 3;;G9AFG8	8*L]^b]efg

5
 KD8STU
VV  	s8D	s   #B	B1B,,B1c           
         d }t        d|dz         D ](  }t                	 t        |        t        d| d        y  t        d|       # t        $ r5}|}t        d| d| d|        t        j                  d       Y d }~rd }~ww xY w)	Nr   u2   reboot: UI hierarchy готова (попытка r   u   reboot: ждём uiautomator r  rD   r   u#   UI hierarchy недоступна: )rR  r   r`   r"   r5   r   r   r3   )r;   r   r  r  r?   s        r   _wait_ui_readyr  A
  s    HHqL) 	 	DWIQOP	 <XJG
HH	  	H/y(2cUKLJJsOO	s   A	B	+BB	c                     	 | j                  d      xs d}t        j                  d|      }|r4t	        |j                  d            t	        |j                  d            fS y# t        $ r d}Y Zw xY w)Nzwm sizerB   z(\d+)\s*x\s*(\d+)r   rk   )i  i   )rH   r5   r   r   r4   r   r.  s      r   _device_screen_sizer  P
  sn    ll9%+ II*C0E5;;q>"CA$777  s   A$ $A21A2c                    t        |       \  }}|dz  }t        dt        |dz              }t        dt        |dz              }t        d| d| d| d| d	| d
| d       | j	                  d| d| d| d| d	       y )Nrk      g333333?r  g)\(?u   reboot: свайп вверх r  z -> u    (экран r   r   zinput swipe rj   z 450)r  r   r4   r"   rH   )r;   r   r   r   y1y2s         r   	_swipe_upr  [
  s    '/ME6
A	S#ftm$	%B	RVd]#	$B
(1RDQCqM%PQRXQYYZ[\
LL<s!B4q1RD56r   c                    dD ],  }	 | j                  d|        t        j                  d       . 	 t        |        t        j                  d       	 | j                  d       t        j                  d       y # t        $ r}t        d| d|        Y d }~d }~ww xY w# t        $ r}t        d|        Y d }~d }~ww xY w# t        $ r Y lw xY w)	N)R   r+   r  zreboot: keyevent rD   r  u/   reboot: свайп разблокировки: r  input keyevent 3)rH   r5   r"   r   r   r  )r;   r  r?   s      r   _unlock_to_homer
  d
  s     	2LL?3%01 	

3E& 	JJsO'( 	JJsO  	2#C53%011	2
  E=cUCDDE
  s@   A;B" C ;	BBB"	C+B>>C	CCc                 ^    t        |       }|t        k(  }t        d|xs d |rdnd        |S )Nu"   reboot: передний план u   —z (Ozon)rB   )r0  r4  r"   )r;   packager   s      r   _ozon_is_foregroundr  w
  s;    $V,G	L	 B
,W-=,>ByTV>WXYIr   c                     t        j                          |z   }t        j                          |k  rCt                t        |       ryt        j                  d       t        j                          |k  rCt        |       S )NTr  )r   r   r  r   r   s      r   _wait_ozon_foregroundr  ~
  sY    yy{W$H
))+
  v&

3	 ))+
 
 v&&r   c                     g }dD ]U  }| j                   j                  |      xs dj                         }|s3|j                  d      rE|j	                  |       W dj                  |      S )Nrh   ri   r)  rB   rl   rj   )rr   rs   rE   rw   rx   rt   )r~   r  r   r   s       r   _node_search_blobr  
  sb    E7  &,"335))*5LL  88E?r   c                    g }| j                         D ]-  }t        |      }|rt        |      dkD  r d}|j                         }d|vr	t        |vr?t
        d   j                  |      st
        d   j                  |      rd}n*t        j                  d|t        j                        rd}nt        |j                  j                  d            }t        |d	
      }||r|d   \  }}	|dkD  r	|	d	kD  r||	f}|d}
|r+t        d|d   |d   z
        t        d|d   |d   z
        z  }
|j                  ||
||f       0 |sy |j                  d       |d   \  }}}}t!        d| d|        |S )Nr  r   ozonr   r+   z\bozon\br   r   r   )r   r   r   r   r   r   T)reverseu   reboot: иконка «u   » @ )rq   r  rv   r   r4  OZON_LAUNCHER_PATTERNSr   r   r   r   rr   rs   r   r   rx   sortr"   )r|   rankedr~   blobscorer2  r   pointr   r   area_score_areas                r   _find_ozon_launcher_pointr  
  s   F		 2 &s4y2~jjlT!9!!$++D15KA5N5U5UVZ5[EYY{D>Edkkooh78 r2=V(#DAq1uRA=q&/F6N:;c!VHEUX^_dXeEe>ffDudE401324 
KKK!'FE5$
!$uUG45Lr   c                    	 t        t        |             }t	        |      }|yg }|j                         D ]!  }t        |      }|s|j                  |       # dj                  t        t        j                  |            d d       }t        d|xs d        yt        | g|  y# t        $ r}t        d|        Y d }~yd }~ww xY w)Nu9   reboot: дамп лаунчера не читается: Fr      uB   reboot: иконка Ozon не найдена. На экране: u
   пустоT)r   r`   r5   r"   r  rq   r  rx   rt   r   ry   rz   r   )r;   r|   r?   r  r}   r~   r  r   s           r   _tap_ozon_launcher_iconr"  
  s    [01 &d+E}IIK 	#D$T*DT"	# ))Du!56s;<PQXQh\hPijkV$e$  GuMNs   B) )	C
2CC
c                 J   t        d       	 | j                  d       t        j                  d       	 t        |        t        j                  d       t        d      D ]V  }t                t        |       rt        d        y	t        d
|dz           	 t        |        t        j                  d       X y# t        $ r}t        d|        Y d }~d }~ww xY w# t        $ r}t        d|        Y d }~d }~ww xY w# t        $ r}t        d|        Y d }~|d }~ww xY w)Nu$   reboot: HOME + свайп вверхr	  u"   reboot: HOME не нажался: r  u1   reboot: свайп вверх не удался: r  r	  u$   reboot: нажал иконку OzonTu?   reboot: «Ozon Банк» не найден, ещё свайп r   u&   reboot: свайп не удался: g?F)	r"   rH   r5   r   r   r  rR  r   r"  )r;   r?   r  s      r   _open_ozon_from_launcherr$  
  s   ./8'( 	JJsOG& 	JJsO8 
 "6*67MgXYk][\	@f 	

3
 )  806778
  G?uEFFG  	@8>??	@sF   B9 C D9	CCC	C>&C99C>	D"
DD"c                    dt          ddt          dt         g}|D ]w  }t        |       r y t        d|        	 | j	                  |      xs d}|j                         rt        d|j                         d d         t        j                  d
       y y # t        $ r}t        d| d	|        Y d }~7d }~ww xY w)Nz
monkey -p z& -c android.intent.category.LAUNCHER 1zNam start -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -p r3  u   reboot: запуск rB   zreboot: ,  r.   r   )	r4  r5  r  r"   rH   rE   r5   r   r   )r;   commandsr  r/  r?   s        r   _launch_ozon_by_intentr(  
  s    
\N"HI
XYeXfg
}o&H
  
v&#G9-.	?,,w'-2Cyy{hsyy{4C0123 	

3
  	?(7)#7u=>>	?s   AB	B="B88B=c                    ddl m} t        d|         t        |         || t        t
        d      }t        |      }|rt        |      t        dt        dd       t        j                  t               t        |       }t        |       t        |       t        |       t        |       t        |       t!        |d	
      s.t        d       t#        |       t!        |d
      st        d      t        d       y)uk   Пересобрать redroid по SSH, подключиться по ADB и открыть Ozon Банк.r   )run_ssh_commandsu   reboot: старт для T)r-   echou6   reboot: SSH-команды выполнены, жду z.0fu    сr  r,   ua   reboot: иконка не открыла приложение, запускаю через intent      (@uG   Ozon Банк не открылся после перезагрузкиu7   reboot: успешно, Ozon Банк на экране)utils.ssh_cmdr*  r"   r  REBOOT_SSH_COMMANDSREBOOT_SSH_TIMEOUTr  r3   REBOOT_ADB_WAITr   r   r  r  r  r
  r$  r  r(  )r#   r*  rV  	ssh_errorr;   s        r   reboot_devicer2  
  s    .
$[M23{#"	G "'*I9%%
@QT@UUXYZJJ+&F 6F6V$ 5opv&$VT:hiiABr   __main__device4)r  )r  Fr   )r   )i  r&     )r  )r  )r+   )g     V@)rH  )rk   )r  )Ng      ^@T)r   )   F)r	  )   )g      .@r  )u   Виртуальнаяu   КлассикаT)-   r   )r   r   )r!  )rK   N)r,  )r   r  r   xml.etree.ElementTreeetreeElementTreern   pathlibr   sysr   r   r   r   rY   r   r\   re   r  
api.db_apippadb.clientr   r0   PILr   utils.tap_one_pointr   REDROID_HOSTREDROID_PORTADB_HOSTADB_PORTr4  r5  	DUMP_PATHr5   r
   r   r   r   r"   r4   r@   rJ   rN   rP   rT   r`   rd   rb   r   r   r   r   r   r   r   r  r   r   r   r   r  r  r  r  r  r  r"  r%  r.  r3  r7  rF  ra  rq  ru  rv  ry  r~  r  r  rS  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  floatr  r  r!  r&  r+  r0  r6  r>  rN  r{  r}  r  r   r  r  r  r  r  r  r  r  r  r  r  r  rQ  r  ry   r  r  r  r  r.  r/  r0  r  r  r  r  r   r  r  r  r   r  r  r
  r  r  r  r  r"  r$  r(  r2  r   r   r   r   <module>rH     s   	 	  " "  
 	 X ''..u:SXXHHOOAs5z"  ,  -(. efFN]*	]i ]  
S  7?PX / / /# /d 5=h 2C 2s 2c 2 2jU ! ! ! ,5 D  *%S % !* + +c +"  )   (C # <&"R)3 ># >mq >B# mq :Sc Sae S
 * 
									Z3 Zd Z> 8, ,4s 4)# )s )t )X #  $  F# $ 2$44 4 44-s -`)S )X LC LD L3 3 	> 	>< < S (# (Vs S>($D $N( (S s QT  =# =@Q
5s 5p4 : %)t$QV : -1t$Y^ 93$ 3# D    D 2 *.u  *  *
% 
4 

3 
C 
PT 
:.	+c 	+: : : '5TeTY ew{ ePvr$	E3 	E3 	E@S @3 @4 @ 	C 	.c .t .X\ .b# &a^3 a^4 a^H+&c +&S +& +&\.>2n?4D(c (3 ( (V -# -	 	 	# t  *"JS 5 SX cg C\S C\S C\rv C\L    :BS[ 4C 43 4S 4$]c ]S ]e ]$t  $ BJJ!2==1BJJ~r}}- W3 WE WD W IS I$ I5c? 7&4 '5 'D 's !Ht ( 6&"s "t "N z Y r   