Skip to content

Commit ee1f302

Browse files
show progress for android device download
1 parent 037a536 commit ee1f302

1 file changed

Lines changed: 136 additions & 22 deletions

File tree

Framework/install_handler/android/emulator.py

Lines changed: 136 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)