@@ -106,6 +106,9 @@ protected void onCreate(Bundle savedInstanceState) {
106106 installStatus = findViewById (R .id .k2go_install_status );
107107 installBar = findViewById (R .id .k2go_install_bar );
108108 installDetail = findViewById (R .id .k2go_install_detail );
109+ // ADFA-4915: extract detail is one middle-ellipsized line so long file names never overlap.
110+ installDetail .setMaxLines (1 );
111+ installDetail .setEllipsize (android .text .TextUtils .TruncateAt .MIDDLE );
109112 installing = getIntent ().getBooleanExtra (EXTRA_INSTALLING , false );
110113 // The Lottie has a text layer (OPEN/CLOSED sign). Use the system typeface (Noto-based,
111114 // global script fallback) so localized words render in any language; a TextDelegate maps
@@ -215,6 +218,24 @@ private void showInstallProgress(InstallState st) {
215218 installBar .setIndeterminate (false );
216219 installBar .setProgress (st .percent );
217220 installDetail .setText (st .percent + "%" + (st .speed .isEmpty () ? "" : " · " + st .speed ));
221+ } else if (st .phase == InstallState .Phase .EXTRACTING ) {
222+ if (st .percent < 0 ) {
223+ // ADFA-4915: "reading/listing" sub-phase. listEntries() scans the whole archive
224+ // (~1 min; longer on low-end devices), so show an animated "reading …" + an
225+ // indeterminate bar instead of a frozen 0%.
226+ startReadingEllipsis (getString (R .string .k2go_reading ));
227+ installBar .setIndeterminate (true );
228+ installDetail .setText ("" );
229+ } else {
230+ // ADFA-4915: determinate extract — real % plus just the current file's basename
231+ // (no internal path, no counter): one ellipsized line that never overlaps.
232+ installStatus .setText (org .iiab .controller .deploy .domain .ExtractProgress .firstLine (
233+ getString (R .string .install_status_extracting )));
234+ installBar .setIndeterminate (false );
235+ installBar .setProgress (st .percent );
236+ String name = org .iiab .controller .deploy .domain .ExtractProgress .fileLabel (st .message );
237+ installDetail .setText (name .isEmpty () ? (st .percent + "%" ) : (st .percent + "% · " + name ));
238+ }
218239 } else {
219240 installStatus .setText (st .message .isEmpty () ? getString (R .string .k2go_setting_up_library ) : st .message );
220241 installBar .setIndeterminate (true );
@@ -495,6 +516,29 @@ private void stopBootEllipsis() {
495516 ellipsisRunnable = null ;
496517 }
497518
519+ /** ADFA-4915: animate "reading" + . / .. / … while the archive is being listed. Reuses the
520+ * ellipsis handler (boot and reading never run at once) without touching {@code bootBaseText}. */
521+ private void startReadingEllipsis (final String base ) {
522+ stopBootEllipsis ();
523+ ellipsisRunnable = new Runnable () {
524+ int i = 0 ;
525+ final String [] frames = {" " , ". " , ".. " , "..." }; // 0..3 dots, fixed 3-slot width (monospace)
526+ @ Override public void run () {
527+ if (installStatus != null ) {
528+ String suffix = frames [i % frames .length ];
529+ android .text .SpannableString sp = new android .text .SpannableString (base + " " + suffix );
530+ sp .setSpan (new android .text .style .TypefaceSpan ("monospace" ),
531+ base .length () + 1 , base .length () + 1 + suffix .length (),
532+ android .text .Spanned .SPAN_EXCLUSIVE_EXCLUSIVE );
533+ installStatus .setText (sp );
534+ }
535+ i ++;
536+ ellipsisHandler .postDelayed (this , 450L );
537+ }
538+ };
539+ ellipsisHandler .post (ellipsisRunnable );
540+ }
541+
498542 @ Override
499543 public void enableSystemProtection () {
500544 Intent i = new Intent (this , WatchdogService .class );
0 commit comments