@@ -864,7 +864,7 @@ def _generate_avd_name(android_version: str, existing_avds: list[str]) -> str:
864864 return f"{ android_version } -{ word1 } -{ word2 } -{ random_num } "
865865
866866
867- def _run_sdkmanager_install_windows (sdkmanager : Path , sdk_root : Path , system_image : str ) -> tuple [bool , str ]:
867+ def _run_sdkmanager_install_windows (sdkmanager : Path , sdk_root : Path , system_image : str , loop = None , device_id : str = None ) -> tuple [bool , str ]:
868868 """Install system image on Windows with real-time output"""
869869 try :
870870 # Use PowerShell to handle the command properly and auto-accept licenses
@@ -892,6 +892,7 @@ def _run_sdkmanager_install_windows(sdkmanager: Path, sdk_root: Path, system_ima
892892 # Print output in real-time as it comes, showing progress on single line
893893 output_lines = []
894894 last_progress = ""
895+ progress_count = []
895896 try :
896897 for line in iter (process .stdout .readline , '' ):
897898 if line :
@@ -901,18 +902,55 @@ def _run_sdkmanager_install_windows(sdkmanager: Path, sdk_root: Path, system_ima
901902 # Extract progress percentage from lines like "[====] 25% Loading..."
902903 progress_match = re .search (r'\[.*?\]\s*(\d+)%\s*(.+)' , stripped )
903904 if progress_match :
904- percent = progress_match .group (1 )
905+ percent = int ( progress_match .group (1 ) )
905906 status = progress_match .group (2 ).strip ()
906907 current_progress = f"{ percent } % { status } "
907908 if current_progress != last_progress :
908909 print (f"\r [installer][emulator] Download progress: { current_progress } " , end = '' , flush = True )
909910 last_progress = current_progress
911+
912+ if loop and device_id :
913+ rounded_percent = round (percent / 10 ) * 10
914+ if rounded_percent not in progress_count :
915+ progress_count .append (rounded_percent )
916+ asyncio .run_coroutine_threadsafe (
917+ send_response ({
918+ "action" : "status" ,
919+ "data" : {
920+ "category" : "AndroidEmulator" ,
921+ "package" : device_id ,
922+ "status" : "installing" ,
923+ "comment" : f"Downloading system image... { percent } % { status } " ,
924+ }
925+ }),
926+ loop
927+ )
910928 elif stripped and not stripped .startswith ('[' ) and '%' not in stripped :
911929 # Print important non-progress messages on new line
912930 print (f"\n [installer][emulator] { stripped } " )
913931 elif stripped .endswith ('%' ):
914932 # Handle lines that end with just percentage
915- print (f"\r [installer][emulator] Download progress: { stripped } " , end = '' , flush = True )
933+ percent_match = re .search (r'(\d+)%' , stripped )
934+ if percent_match :
935+ percent = int (percent_match .group (1 ))
936+ print (f"\r [installer][emulator] Download progress: { stripped } " , end = '' , flush = True )
937+
938+ if loop and device_id :
939+ rounded_percent = round (percent / 10 ) * 10
940+ if rounded_percent not in progress_count :
941+ progress_count .append (rounded_percent )
942+ asyncio .run_coroutine_threadsafe (
943+ send_response ({
944+ "action" : "status" ,
945+ "data" : {
946+ "category" : "AndroidEmulator" ,
947+ "package" : device_id ,
948+ "status" : "installing" ,
949+ "comment" : f"Downloading system image... { percent } %" ,
950+ }
951+ }),
952+ loop
953+ )
916954 except Exception as e :
917955 print (f"\n [installer][emulator] Output reading error: { e } " )
918956 finally :
@@ -932,7 +970,7 @@ def _run_sdkmanager_install_windows(sdkmanager: Path, sdk_root: Path, system_ima
932970 return False , str (e )
933971
934972
935- def _run_sdkmanager_install_linux (sdkmanager : Path , sdk_root : Path , system_image : str ) -> tuple [bool , str ]:
973+ def _run_sdkmanager_install_linux (sdkmanager : Path , sdk_root : Path , system_image : str , loop = None , device_id : str = None ) -> tuple [bool , str ]:
936974 """Install system image on Linux with real-time output"""
937975 try :
938976 if debug :
@@ -950,6 +988,7 @@ def _run_sdkmanager_install_linux(sdkmanager: Path, sdk_root: Path, system_image
950988 # Print output in real-time as it comes, showing progress on single line
951989 output_lines = []
952990 last_progress = ""
991+ progress_count = []
953992 try :
954993 for line in iter (process .stdout .readline , '' ):
955994 if line :
@@ -959,18 +998,55 @@ def _run_sdkmanager_install_linux(sdkmanager: Path, sdk_root: Path, system_image
959998 # Extract progress percentage from lines like "[====] 25% Loading..."
960999 progress_match = re .search (r'\[.*?\]\s*(\d+)%\s*(.+)' , stripped )
9611000 if progress_match :
962- percent = progress_match .group (1 )
1001+ percent = int ( progress_match .group (1 ) )
9631002 status = progress_match .group (2 ).strip ()
9641003 current_progress = f"{ percent } % { status } "
9651004 if current_progress != last_progress :
9661005 print (f"\r [installer][emulator] Download progress: { current_progress } " , end = '' , flush = True )
9671006 last_progress = current_progress
1007+
1008+ if loop and device_id :
1009+ rounded_percent = round (percent / 10 ) * 10
1010+ if rounded_percent not in progress_count :
1011+ progress_count .append (rounded_percent )
1012+ asyncio .run_coroutine_threadsafe (
1013+ send_response ({
1014+ "action" : "status" ,
1015+ "data" : {
1016+ "category" : "AndroidEmulator" ,
1017+ "package" : device_id ,
1018+ "status" : "installing" ,
1019+ "comment" : f"Downloading system image... { percent } % { status } " ,
1020+ }
1021+ }),
1022+ loop
1023+ )
9681024 elif stripped and not stripped .startswith ('[' ) and '%' not in stripped :
9691025 # Print important non-progress messages on new line
9701026 print (f"\n [installer][emulator] { stripped } " )
9711027 elif stripped .endswith ('%' ):
9721028 # Handle lines that end with just percentage
973- print (f"\r [installer][emulator] Download progress: { stripped } " , end = '' , flush = True )
1029+ percent_match = re .search (r'(\d+)%' , stripped )
1030+ if percent_match :
1031+ percent = int (percent_match .group (1 ))
1032+ print (f"\r [installer][emulator] Download progress: { stripped } " , end = '' , flush = True )
1033+
1034+ if loop and device_id :
1035+ rounded_percent = round (percent / 10 ) * 10
1036+ if rounded_percent not in progress_count :
1037+ progress_count .append (rounded_percent )
1038+ asyncio .run_coroutine_threadsafe (
1039+ send_response ({
1040+ "action" : "status" ,
1041+ "data" : {
1042+ "category" : "AndroidEmulator" ,
1043+ "package" : device_id ,
1044+ "status" : "installing" ,
1045+ "comment" : f"Downloading system image... { percent } %" ,
1046+ }
1047+ }),
1048+ loop
1049+ )
9741050 except Exception as e :
9751051 print (f"\n [installer][emulator] Output reading error: { e } " )
9761052 finally :
@@ -990,7 +1066,7 @@ def _run_sdkmanager_install_linux(sdkmanager: Path, sdk_root: Path, system_image
9901066 return False , str (e )
9911067
9921068
993- def _run_sdkmanager_install_darwin (sdkmanager : Path , sdk_root : Path , system_image : str ) -> tuple [bool , str ]:
1069+ def _run_sdkmanager_install_darwin (sdkmanager : Path , sdk_root : Path , system_image : str , loop = None , device_id : str = None ) -> tuple [bool , str ]:
9941070 """Install system image on macOS with real-time output"""
9951071 try :
9961072 if debug :
@@ -1008,6 +1084,7 @@ def _run_sdkmanager_install_darwin(sdkmanager: Path, sdk_root: Path, system_imag
10081084 # Print output in real-time as it comes, showing progress on single line
10091085 output_lines = []
10101086 last_progress = ""
1087+ progress_count = []
10111088 try :
10121089 for line in iter (process .stdout .readline , '' ):
10131090 if line :
@@ -1017,18 +1094,55 @@ def _run_sdkmanager_install_darwin(sdkmanager: Path, sdk_root: Path, system_imag
10171094 # Extract progress percentage from lines like "[====] 25% Loading..."
10181095 progress_match = re .search (r'\[.*?\]\s*(\d+)%\s*(.+)' , stripped )
10191096 if progress_match :
1020- percent = progress_match .group (1 )
1097+ percent = int ( progress_match .group (1 ) )
10211098 status = progress_match .group (2 ).strip ()
10221099 current_progress = f"{ percent } % { status } "
10231100 if current_progress != last_progress :
10241101 print (f"\r [installer][emulator] Download progress: { current_progress } " , end = '' , flush = True )
10251102 last_progress = current_progress
1103+
1104+ if loop and device_id :
1105+ rounded_percent = round (percent / 10 ) * 10
1106+ if rounded_percent not in progress_count :
1107+ progress_count .append (rounded_percent )
1108+ asyncio .run_coroutine_threadsafe (
1109+ send_response ({
1110+ "action" : "status" ,
1111+ "data" : {
1112+ "category" : "AndroidEmulator" ,
1113+ "package" : device_id ,
1114+ "status" : "installing" ,
1115+ "comment" : f"Downloading system image... { percent } % { status } " ,
1116+ }
1117+ }),
1118+ loop
1119+ )
10261120 elif stripped and not stripped .startswith ('[' ) and '%' not in stripped :
10271121 # Print important non-progress messages on new line
10281122 print (f"\n [installer][emulator] { stripped } " )
10291123 elif stripped .endswith ('%' ):
10301124 # Handle lines that end with just percentage
1031- print (f"\r [installer][emulator] Download progress: { stripped } " , end = '' , flush = True )
1125+ percent_match = re .search (r'(\d+)%' , stripped )
1126+ if percent_match :
1127+ percent = int (percent_match .group (1 ))
1128+ print (f"\r [installer][emulator] Download progress: { stripped } " , end = '' , flush = True )
1129+
1130+ if loop and device_id :
1131+ rounded_percent = round (percent / 10 ) * 10
1132+ if rounded_percent not in progress_count :
1133+ progress_count .append (rounded_percent )
1134+ asyncio .run_coroutine_threadsafe (
1135+ send_response ({
1136+ "action" : "status" ,
1137+ "data" : {
1138+ "category" : "AndroidEmulator" ,
1139+ "package" : device_id ,
1140+ "status" : "installing" ,
1141+ "comment" : f"Downloading system image... { percent } %" ,
1142+ }
1143+ }),
1144+ loop
1145+ )
10321146 except Exception as e :
10331147 print (f"\n [installer][emulator] Output reading error: { e } " )
10341148 finally :
@@ -1337,6 +1451,7 @@ async def create_avd_from_system_image(device_param: str) -> bool:
13371451 if len (parts ) < 3 :
13381452 error_msg = f"Invalid device parameter format. Expected 'install device;device_id;device_name', got: { device_param } "
13391453 print (f"[installer][emulator] { error_msg } " )
1454+ device_id = parts [1 ].strip () if len (parts ) > 1 else "unknown"
13401455 await send_response ({
13411456 "action" : "status" ,
13421457 "data" : {
@@ -1451,15 +1566,6 @@ async def create_avd_from_system_image(device_param: str) -> bool:
14511566
14521567 # Step 1: Install system image
14531568 print (f"[installer][emulator] Installing system image: { system_image_name } " )
1454- await send_response ({
1455- "action" : "status" ,
1456- "data" : {
1457- "category" : "AndroidEmulator" ,
1458- "package" : device_id ,
1459- "status" : "installing" ,
1460- "comment" : "Download started. Check the terminal on which ZeuZ Node is open for updates" ,
1461- }
1462- })
14631569
14641570 loop = asyncio .get_event_loop ()
14651571 if _is_windows ():
@@ -1468,23 +1574,29 @@ async def create_avd_from_system_image(device_param: str) -> bool:
14681574 _run_sdkmanager_install_windows ,
14691575 sdkmanager ,
14701576 sdk_root ,
1471- system_image_name
1577+ system_image_name ,
1578+ loop ,
1579+ device_id
14721580 )
14731581 elif _is_linux ():
14741582 success , output = await loop .run_in_executor (
14751583 None ,
14761584 _run_sdkmanager_install_linux ,
14771585 sdkmanager ,
14781586 sdk_root ,
1479- system_image_name
1587+ system_image_name ,
1588+ loop ,
1589+ device_id
14801590 )
14811591 elif _is_darwin ():
14821592 success , output = await loop .run_in_executor (
14831593 None ,
14841594 _run_sdkmanager_install_darwin ,
14851595 sdkmanager ,
14861596 sdk_root ,
1487- system_image_name
1597+ system_image_name ,
1598+ loop ,
1599+ device_id
14881600 )
14891601 else :
14901602 # Fallback to Linux for unknown platforms
@@ -1493,7 +1605,9 @@ async def create_avd_from_system_image(device_param: str) -> bool:
14931605 _run_sdkmanager_install_linux ,
14941606 sdkmanager ,
14951607 sdk_root ,
1496- system_image_name
1608+ system_image_name ,
1609+ loop ,
1610+ device_id
14971611 )
14981612
14991613 if not success :
0 commit comments