@@ -280,38 +280,43 @@ private JPanel createDeviceCard(EmulatorService.AvdInfo avd) {
280280 BorderFactory .createEmptyBorder (10 , 10 , 10 , 10 )
281281 ));
282282 card .setPreferredSize (new Dimension (180 , 200 ));
283- card .setCursor (new Cursor (Cursor .HAND_CURSOR ));
284283
285- // Device name at top
284+ // Top panel with name and info
285+ JPanel topPanel = new JPanel (new BorderLayout (3 , 3 ));
286+
287+ // Device name
286288 JLabel nameLabel = new JLabel (avd .name (), SwingConstants .CENTER );
287289 nameLabel .setFont (nameLabel .getFont ().deriveFont (Font .BOLD , 14f ));
288- card .add (nameLabel , BorderLayout .NORTH );
290+ topPanel .add (nameLabel , BorderLayout .NORTH );
289291
290- // Details panel (initially hidden, toggled on click)
291- JPanel detailsPanel = new JPanel (new GridLayout (0 , 1 , 2 , 2 ));
292- detailsPanel .setVisible (false );
292+ // Info panel with version and device type (ALWAYS VISIBLE)
293+ JPanel infoPanel = new JPanel (new GridLayout (0 , 1 , 2 , 2 ));
293294
294- // Extract API level and convert to Android version name
295- String apiLevel = extractApiLevel (avd .target ());
295+ // Extract API level from config.ini (more reliable than target string)
296+ String apiLevel = extractApiLevelFromPath (avd .path ());
296297 String androidVersion = getAndroidVersionName (apiLevel );
297- JLabel versionLabel = new JLabel ("📱 " + androidVersion );
298- versionLabel .setFont (versionLabel .getFont ().deriveFont (Font .BOLD ));
299- detailsPanel .add (versionLabel );
298+ JLabel versionLabel = new JLabel (androidVersion , SwingConstants . CENTER );
299+ versionLabel .setFont (versionLabel .getFont ().deriveFont (Font .PLAIN , 11f ));
300+ infoPanel .add (versionLabel );
300301
301- // Show device type from path (e.g., pixel_7)
302+ // Show device type
302303 String deviceType = extractDeviceType (avd .path ());
303304 if (deviceType != null && !deviceType .isEmpty ()) {
304- detailsPanel .add (new JLabel ("📐 Device: " + deviceType ));
305+ JLabel deviceLabel = new JLabel (deviceType , SwingConstants .CENTER );
306+ deviceLabel .setFont (deviceLabel .getFont ().deriveFont (Font .PLAIN , 10f ));
307+ deviceLabel .setForeground (Color .GRAY );
308+ infoPanel .add (deviceLabel );
305309 }
306310
307311 // Check if running
308312 boolean isRunning = emulatorService != null && emulatorService .isEmulatorRunning (avd .name ());
309- JLabel statusLabel = new JLabel (isRunning ? "🟢 Running" : "⚪ Stopped" );
310- statusLabel .setFont (statusLabel .getFont ().deriveFont (Font .BOLD ));
313+ JLabel statusLabel = new JLabel (isRunning ? "● Running" : "○ Stopped" , SwingConstants . CENTER );
314+ statusLabel .setFont (statusLabel .getFont ().deriveFont (Font .BOLD , 10f ));
311315 statusLabel .setForeground (isRunning ? new Color (76 , 175 , 80 ) : Color .GRAY );
312- detailsPanel .add (statusLabel );
316+ infoPanel .add (statusLabel );
313317
314- card .add (detailsPanel , BorderLayout .CENTER );
318+ topPanel .add (infoPanel , BorderLayout .CENTER );
319+ card .add (topPanel , BorderLayout .NORTH );
315320
316321 // Action buttons panel
317322 JPanel actionsPanel = new JPanel (new GridLayout (2 , 2 , 5 , 5 ));
@@ -345,21 +350,43 @@ private JPanel createDeviceCard(EmulatorService.AvdInfo avd) {
345350
346351 card .add (actionsPanel , BorderLayout .SOUTH );
347352
348- // Toggle details on card click
349- card .addMouseListener (new java .awt .event .MouseAdapter () {
350- @ Override
351- public void mouseClicked (java .awt .event .MouseEvent e ) {
352- detailsPanel .setVisible (!detailsPanel .isVisible ());
353- card .revalidate ();
354- card .repaint ();
353+ return card ;
354+ }
355+
356+ /**
357+ * Extracts API level from AVD config.ini file.
358+ * This is more reliable than parsing the target string.
359+ */
360+ private String extractApiLevelFromPath (String avdPath ) {
361+ if (avdPath == null ) return "Unknown" ;
362+
363+ try {
364+ Path configIni = Path .of (avdPath ).resolve ("config.ini" );
365+ if (Files .exists (configIni )) {
366+ String content = Files .readString (configIni );
367+ // Look for image.sysdir.1=system-images/android-35/google_apis/x86_64/
368+ for (String line : content .split ("\n " )) {
369+ if (line .startsWith ("image.sysdir.1=" )) {
370+ String sysdir = line .substring (15 ).trim ();
371+ // Extract API number from: system-images/android-35/google_apis/x86_64/
372+ String [] parts = sysdir .split ("/" );
373+ for (String part : parts ) {
374+ if (part .startsWith ("android-" )) {
375+ return part .substring (8 ); // Remove "android-" prefix
376+ }
377+ }
378+ }
379+ }
355380 }
356- });
381+ } catch (Exception e ) {
382+ logger .debug ("Could not extract API level from path: {}" , avdPath );
383+ }
357384
358- return card ;
385+ return "Unknown" ;
359386 }
360387
361388 /**
362- * Extracts API level from target string.
389+ * Extracts API level from target string (fallback method) .
363390 */
364391 private String extractApiLevel (String target ) {
365392 if (target == null ) return "Unknown" ;
0 commit comments