Spectatio: framework de prueba para Automotive

Spectatio es un framework de prueba de código abierto desarrollado para probar el SO Android Automotive (AAOS) en dispositivos reales y virtuales. Spectatio proporciona APIs para probar apps en un dispositivo automotriz y es una solución extensible y escalable que se usa para verificar la capacidad y el rendimiento de AAOS y sus apps.

Diseño de alto nivel

El framework de Spectatio es adaptable y expandible para diversas implementaciones de la IU de AAOS. Se usa para probar la capacidad y el rendimiento de AAOS en hardware de dispositivos, emuladores y entornos virtualizados.

En la siguiente figura, se explica el diseño de alto nivel del framework de Spectatio.

Diseño de alto nivel del framework de Spectatio

Figura 1: Diseño de alto nivel del framework de Spectatio.

El framework de Spectatio, creado sobre UI Automator, proporciona un conjunto de APIs para compilar pruebas de IU que interactúan con apps del usuario y del sistema en AAOS. Las pruebas de Automotive usan las APIs que proporciona el framework de Spectatio para las pruebas, lo que hace que estas pruebas sean independientes del dispositivo bajo prueba (DUT) y escalables para probar diversos dispositivos, si se admiten.

En la figura 1, se muestra que el framework de Spectatio se modulariza en función de apps de referencia, como Teléfono, Medicenter y Configuración, con interfaces y asistentes específicos de la app, lo que facilita su extensión para apps nuevas. El framework de Spectatio reutiliza las clases auxiliares de utilidad y estándar comunes. La clase auxiliar estándar es la clase principal de todas las funciones auxiliares de la app y proporciona funciones estándar que son específicas del dispositivo o aplicables en todas las apps. Las clases auxiliares de utilidad proporcionan utilidades, como la lectura o escritura de archivos desde el dispositivo.

Arquitectura

Para proporcionar un conjunto de APIs para compilar pruebas de IU, el framework de Spectatio implementa interfaces y asistentes específicos de la app, a la vez que extiende la clase de asistente estándar existente y, también, importa las clases de asistente de utilidad.

En la figura 2, se ilustra la arquitectura de alto nivel del framework de Spectatio y todas las entidades involucradas en la implementación de APIs para probar una app.

Arquitectura de alto nivel del framework de Spectatio

Figura 2: Arquitectura de alto nivel del framework de Spectatio.

La interfaz de asistente de la app proporciona un plan para la implementación de un asistente de la app. Consta de varias funciones auxiliares necesarias para probar apps. Cada app tiene su propia interfaz, como IAutoSettingHelper y IAutoDialHelper. Para obtener más información y una lista de las funciones de la interfaz, consulta las funciones de la interfaz de asistente de la app en AOSP.

La clase auxiliar estándar consta de atributos y funciones estándar que son necesarios para la configuración del dispositivo, pero no son específicos de ninguna app, como pressHome y scroll. La clase de ayuda estándar se define en AbstractAutoStandardAppHelper.java.

El framework usa las clases de asistentes de utilidad. Por ejemplo, AutoJsonUtility.java es una clase de utilidad que carga el archivo de configuración JSON del dispositivo determinado y actualiza los parámetros de configuración del framework en el tiempo de ejecución.

El módulo de implementación de la app de ayuda es el núcleo del framework de Spectatio. Contiene la implementación de las funciones auxiliares definidas en la interfaz de ayuda de la app, que son necesarias para probar apps en un dispositivo para automóviles. Cada app tiene su propia implementación, como SettingHelperImpl y DialHelperImpl, que usan las pruebas de Automotive para probar las apps. Para obtener más información y una lista de implementaciones, consulta las funciones de implementación de asistentes de la app en AOSP.

Las pruebas de Automotive usan las funciones de implementación del asistente de la app para probar varias operaciones relacionadas con la app. Usa la clase HelperAccessor para acceder a las funciones de implementación del asistente de la app.

En el siguiente código, se muestran la configuración, la limpieza y la ejecución de una prueba automotriz de ejemplo.

@RunWith(AndroidJUnit4.class)
public class AutoApplicationTest {
  static HelperAccessor<IAutoApplicationHelper> autoApplicationHelper =
          new HelperAccessor<>(IAutoApplicationHelper.class);

  public AutoApplicationTest() {
    // constructor
    // Initialize any attributes that are required for the test execution
  }

  @Before
  public void beforeTest() {
    // Initial setup before each test
    // For example - open the app
    autoApplicationHelper.open();
  }

  @After
  public void afterTest() {
    // Cleanup after each test.
    // For example - exit the app
    autoApplicationHelper.exit();
  }

  @Test
  public void testApplicationFeature() {
    // Test
    // For example - Test if app is open
    assertTrue("Application is not open.", autoApplicationHelper.isOpen());
  }
}

Personalización

El framework de Spectatio es independiente de la IU del dispositivo, por lo que se puede escalar para probar dispositivos con IU y hardware variados. Para lograr esta escalabilidad, Spectatio usa la configuración predeterminada del dispositivo según el dispositivo de referencia. Para admitir configuraciones de dispositivos no predeterminadas, el framework usa un archivo de configuración JSON en el tiempo de ejecución para establecer los cambios deseados en la IU del dispositivo. Un archivo de configuración JSON admite elementos de la IU, como TEXT, DESCRIPTION y RESOURCE_ID, junto con la configuración de path, y solo debe contener la información sobre los cambios en la IU del DUT. El resto de los elementos de la IU usan los valores de configuración predeterminados que se proporcionan en el framework.

Configuraciones predeterminadas del dispositivo

En el siguiente archivo de configuración JSON de ejemplo, se muestran las configuraciones de dispositivos disponibles y sus valores predeterminados.

Haz clic aquí para mostrar un archivo de configuración JSON de ejemplo.

    {
        "SETTINGS": {
                "APPLICATION_CONFIG": {
                        "SETTINGS_TITLE_TEXT": "Settings",
                        "SETTINGS_PACKAGE": "com.android.car.settings",
                        "SETTINGS_RRO_PACKAGE": "com.android.car.settings.googlecarui.rro",
                        "OPEN_SETTINGS_COMMAND": "am start -a android.settings.SETTINGS",
                        "OPEN_QUICK_SETTINGS_COMMAND": "am start -n com.android.car.settings/com.android.car.settings.common.CarSettingActivity"
                },
                "QUICK_SETTINGS": {
                        "OPEN_MORE_SETTINGS": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "toolbar_menu_item_1",
                                "PACKAGE": "com.android.car.settings"
                        },
                        "NIGHT_MODE": {
                                "TYPE": "TEXT",
                                "VALUE": "Night mode"
                        }
                },
                "DISPLAY": {
                        "PATH": "Settings > Display",
                        "OPTIONS": [
                                "Brightness level"
                        ],
                        "BRIGHTNESS_LEVEL": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "seekbar",
                                "PACKAGE": "com.android.car.settings"
                        }
                },
                "SOUND": {
                        "PATH": "Settings > Sound",
                        "OPTIONS": [
                                "Media volume",
                                "Alarm volume"
                        ]
                },
                "NETWORK_AND_INTERNET": {
                        "PATH": "Settings > Network & internet",
                        "OPTIONS": [
                        ],
                        "TOGGLE_WIFI": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "master_switch",
                                "PACKAGE": "com.android.car.settings"
                        }
                },
                "BLUETOOTH": {
                        "PATH": "Settings > Bluetooth",
                        "OPTIONS": [
                        ],
                        "TOGGLE_BLUETOOTH": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "car_ui_toolbar_menu_item_switch",
                                "PACKAGE": "com.android.car.settings"
                        }
                },
                "APPS_AND_NOTIFICATIONS": {
                        "PATH": "Settings > Apps & notifications",
                        "OPTIONS": [
                        ],
                        "SHOW_ALL_APPS": {
                                "TYPE": "TEXT",
                                "VALUE": "Show all apps"
                        },
                        "ENABLE_DISABLE_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "car_ui_toolbar_menu_item_text",
                                "PACKAGE": "com.android.car.settings"
                        },
                        "DISABLE_BUTTON_TEXT": {
                                "TYPE": "TEXT",
                                "VALUE": "Disable"
                        },
                        "ENABLE_BUTTON_TEXT": {
                                "TYPE": "TEXT",
                                "VALUE": "Enable"
                        },
                        "DISABLE_APP_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "DISABLE APP"
                        },
                        "FORCE_STOP_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Force stop"
                        },
                        "OK_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "OK"
                        },
                        "PERMISSIONS_MENU": {
                                "TYPE": "TEXT",
                                "VALUE": "Permissions"
                        },
                        "ALLOW_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Allow"
                        },
                        "DENY_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Deny"
                        },
                        "DENY_ANYWAY_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Deny anyway"
                        }
                },
                "DATE_AND_TIME": {
                        "PATH": "Settings > Date & time",
                        "OPTIONS": [
                                "Automatic date & time",
                "Automatic time zone"
                        ],
                        "AUTOMATIC_DATE_AND_TIME": {
                                "TYPE": "TEXT",
                                "VALUE": "Automatic date & time"
                        },
                        "AUTOMATIC_TIME_ZONE": {
                                "TYPE": "TEXT",
                                "VALUE": "Automatic time zone"
                        },
                        "SET_DATE": {
                                "TYPE": "TEXT",
                                "VALUE": "Set date"
                        },
                        "SET_TIME": {
                                "TYPE": "TEXT",
                                "VALUE": "Set time"
                        },
                        "SELECT_TIME_ZONE": {
                                "TYPE": "TEXT",
                                "VALUE": "Select time zone"
                        },
                        "USE_24_HOUR_FORMAT": {
                                "TYPE": "TEXT",
                                "VALUE": "Use 24-hour format"
                        },
                        "OK_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "toolbar_menu_item_0",
                                "PACKAGE": "com.android.car.settings"
                        },
                        "NUMBER_PICKER_WIDGET": {
                                "TYPE": "CLASS",
                                "VALUE": "android.widget.NumberPicker"
                        },
                        "EDIT_TEXT_WIDGET": {
                                "TYPE": "CLASS",
                                "VALUE": "android.widget.EditText"
                        }
                },
                "USERS": {
                        "PATH": "Settings > Users",
                        "OPTIONS": [
                                "Guest"
                        ]
                },
                "ACCOUNTS": {
                        "PATH": "Settings > Accounts",
                        "OPTIONS": [
                                "Automatically sync data"
                        ],
                        "ADD_ACCOUNT": {
                                "TYPE": "TEXT",
                                "VALUE": "ADD ACCOUNT"
                        },
                        "ADD_GOOGLE_ACCOUNT": {
                                "TYPE": "TEXT",
                                "VALUE": "Google"
                        },
                        "SIGN_IN_ON_CAR_SCREEN": {
                                "TYPE": "TEXT",
                                "VALUE": "Sign in on car screen"
                        },
                        "GOOGLE_SIGN_IN_SCREEN": {
                                "TYPE": "TEXT",
                                "VALUE": "Sign in to your Google Account"
                        },
                        "ENTER_EMAIL": {
                                "TYPE": "CLASS",
                                "VALUE": "android.widget.EditText"
                        },
                        "ENTER_PASSWORD": {
                                "TYPE": "CLASS",
                                "VALUE": "android.widget.EditText"
                        },
                        "NEXT_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Next"
                        },
                        "DONE_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Done"
                        },
                        "REMOVE_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Remove"
                        },
                        "REMOVE_ACCOUNT_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Remove Account"
                        }
                },
                "SYSTEM": {
                        "PATH": "Settings > System",
                        "OPTIONS": [
                                "About", "Legal information"
                        ],
                        "ABOUT_MENU": {
                                "TYPE": "TEXT",
                                "VALUE": "About"
                        },
                        "RESET_OPTIONS_MENU": {
                                "TYPE": "TEXT",
                                "VALUE": "Reset options"
                        },
                        "LANGUAGES_AND_INPUT_MENU": {
                                "TYPE": "TEXT",
                                "VALUE": "Languages & input"
                        },
                        "DEVICE_MODEL": {
                                "TYPE": "TEXT",
                                "VALUE": "Model"
                        },
                        "ANDROID_VERSION": {
                                "TYPE": "TEXT",
                                "VALUE": "Android version"
                        },
                        "ANDROID_SECURITY_PATCH_LEVEL": {
                                "TYPE": "TEXT",
                                "VALUE": "Android security patch level"
                        },
                        "KERNEL_VERSION": {
                                "TYPE": "TEXT",
                                "VALUE": "Kernel version"
                        },
                        "BUILD_NUMBER": {
                                "TYPE": "TEXT",
                                "VALUE": "Build number"
                        },
                        "RECYCLER_VIEW_WIDGET": {
                                "TYPE": "CLASS",
                                "VALUE": "androidx.recyclerview.widget.RecyclerView"
                        },
                        "RESET_NETWORK": {
                                "TYPE": "TEXT",
                                "VALUE": "Reset network"
                        },
                        "RESET_SETTINGS": {
                                "TYPE": "TEXT",
                                "VALUE": "RESET SETTINGS"
                        },
                        "RESET_APP_PREFERENCES": {
                                "TYPE": "TEXT",
                                "VALUE": "Reset app preferences"
                        },
                        "RESET_APPS": {
                                "TYPE": "TEXT",
                                "VALUE": "RESET APPS"
                        },
                        "LANGUAGES_MENU": {
                                "TYPE": "TEXT",
                                "VALUE": "Languages"
                        },
                        "LANGUAGES_MENU_IN_SELECTED_LANGUAGE": {
                                "TYPE": "TEXT",
                                "VALUE": "Idiomas"
                        }
                },
                "SECURITY": {
                        "PATH": "Settings > Security",
                        "OPTIONS": [
                        ],
                        "TITLE": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "car_ui_toolbar_title",
                                "PACKAGE": "com.android.car.settings.googlecarui.rro"
                        },
                        "CHOOSE_LOCK_TYPE": {
                                "TYPE": "TEXT",
                                "VALUE": "Choose a lock type"
                        },
                        "LOCK_TYPE_PASSWORD": {
                                "TYPE": "TEXT",
                                "VALUE": "Password"
                        },
                        "LOCK_TYPE_PIN": {
                                "TYPE": "TEXT",
                                "VALUE": "PIN"
                        },
                        "LOCK_TYPE_NONE": {
                                "TYPE": "TEXT",
                                "VALUE": "None"
                        },
                        "CONTINUE_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Continue"
                        },
                        "CONFIRM_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Confirm"
                        },
                        "ENTER_PASSWORD": {
                                "TYPE": "CLASS",
                                "VALUE": "android.widget.EditText"
                        },
                        "PIN_PAD": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "pin_pad",
                                "PACKAGE": "com.android.car.settings"
                        },
                        "ENTER_PIN_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "key_enter",
                                "PACKAGE": "com.android.car.settings"
                        },
                        "REMOVE_BUTTON": {
                                "TYPE": "TEXT",
                                "VALUE": "Remove"
                        }
                }
        },
        "PHONE": {
                "APPLICATION_CONFIG": {
                        "DIAL_PACKAGE": "com.android.car.dialer",
                        "PHONE_ACTIVITY": "com.android.car.dialer/.ui.TelecomActivity",
                        "OPEN_DIAL_PAD_COMMAND": "am start -a android.intent.action.DIAL"
                },
                "IN_CALL_VIEW": {
                        "DIALED_CONTACT_TITLE": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "user_profile_title",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "DIALED_CONTACT_NUMBER": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "user_profile_phone_number",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "END_CALL": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "end_call_button",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "MUTE_CALL": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "mute_button",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "SWITCH_TO_DIAL_PAD": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "toggle_dialpad_button",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "CHANGE_VOICE_CHANNEL": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "voice_channel_view",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "VOICE_CHANNEL_CAR": {
                                "TYPE": "TEXT",
                                "VALUE": "Car speakers"
                        },
                        "VOICE_CHANNEL_PHONE": {
                                "TYPE": "TEXT",
                                "VALUE": "Phone"
                        }
                },
                "DIAL_PAD_VIEW": {
                        "DIAL_PAD_MENU": {
                                "TYPE": "TEXT",
                                "VALUE": "Dial Pad"
                        },
                        "DIAL_PAD_FRAGMENT": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "dialpad_fragment",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "DIALED_NUMBER": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "title",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "MAKE_CALL": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "call_button",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "DELETE_NUMBER": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "delete_button",
                                "PACKAGE": "com.android.car.dialer"
                        }
                },
                "CONTACTS_VIEW": {
                        "CONTACTS_MENU": {
                                "TYPE": "TEXT",
                                "VALUE": "Contacts"
                        },
                        "CONTACT_INFO": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "call_action_id",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "CONTACT_NAME": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "title",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "CONTACT_DETAIL": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "show_contact_detail_id",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "ADD_CONTACT_TO_FAVORITE": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "contact_details_favorite_button",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "SEARCH_CONTACT": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "menu_item_search",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "CONTACT_SEARCH_BAR": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "car_ui_toolbar_search_bar",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "SEARCH_RESULT": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "contact_name",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "CONTACT_SETTINGS": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "menu_item_setting",
                                "PACKAGE": "com.android.car.dialer"
                        },
                        "CONTACT_ORDER": {
                                "TYPE": "TEXT",
                                "VALUE": "Contact order"
                        },
                        "SORT_BY_FIRST_NAME": {
                                "TYPE": "TEXT",
                                "VALUE": "First name"
                        },
                        "SORT_BY_LAST_NAME": {
                                "TYPE": "TEXT",
                                "VALUE": "Last Name"
                        },
                        "CONTACT_TYPE_WORK": {
                                "TYPE": "TEXT",
                                "VALUE": "Work"
                        },
                        "CONTACT_TYPE_MOBILE": {
                                "TYPE": "TEXT",
                                "VALUE": "Mobile"
                        },
                        "CONTACT_TYPE_HOME": {
                                "TYPE": "TEXT",
                                "VALUE": "Home"
                        }
                },
                "CALL_HISTORY_VIEW": {
                        "CALL_HISTORY_MENU": {
                                "TYPE": "TEXT",
                                "VALUE": "Recents"
                        },
                        "CALL_HISTORY_INFO": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "call_action_id",
                                "PACKAGE": "com.android.car.dialer"
                        }
                },
                "FAVORITES_VIEW": {
                        "FAVORITES_MENU": {
                                "TYPE": "TEXT",
                                "VALUE": "Favorites"
                        }
                }
        },
        "NOTIFICATIONS": {
                "APPLICATION_CONFIG": {
                        "OPEN_NOTIFICATIONS_COMMAND": "service call statusbar 1"
                },
                "EXPANDED_NOTIFICATIONS_SCREEN": {
                        "NOTIFICATION_VIEW": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "notification_view",
                                "PACKAGE": "com.android.systemui"
                        },
                        "CLEAR_ALL_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "clear_all_button",
                                "PACKAGE": "com.android.systemui"
                        },
                        "STATUS_BAR": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "car_top_navigation_bar_container",
                                "PACKAGE": "com.android.systemui"
                        },
                        "APP_ICON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "app_icon",
                                "PACKAGE": "com.android.systemui"
                        },
                        "APP_NAME": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "header_text",
                                "PACKAGE": "com.android.systemui"
                        },
                        "NOTIFICATION_TITLE": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "notification_body_title",
                                "PACKAGE": "com.android.systemui"
                        },
                        "NOTIFICATION_BODY": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "notification_body_content",
                                "PACKAGE": "com.android.systemui"
                        },
                        "CARD_VIEW": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "card_view",
                                "PACKAGE": "com.android.systemui"
                        }
                }
        },
        "MEDIA_CENTER": {
                "APPLICATION_CONFIG": {
                        "MEDIA_CENTER_PACKAGE": "com.android.car.media",
                        "MEDIA_ACTIVITY": "com.android.bluetooth/com.android.bluetooth.avrcpcontroller.BluetoothMediaBrowserService"
                },
                "MEDIA_CENTER_SCREEN": {
                        "PLAY_PAUSE_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "play_pause_stop",
                                "PACKAGE": "com.android.car.media"
                        },
                        "NEXT_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "skip_next",
                                "PACKAGE": "com.android.car.media"
                        },
                        "PREVIOUS_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "skip_prev",
                                "PACKAGE": "com.android.car.media"
                        },
                        "SHUFFLE_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "overflow_on",
                                "PACKAGE": "com.android.car.media"
                        },
                        "PLAY_QUEUE_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "play_queue",
                                "PACKAGE": "com.android.car.media"
                        },
                        "MINIMIZED_MEDIA_CONTROLS": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "minimized_playback_controls",
                                "PACKAGE": "com.android.car.media"
                        },
                        "TRACK_NAME": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "title",
                                "PACKAGE": "com.android.car.media"
                        },
                        "TRACK_NAME_MINIMIZED_CONTROL": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "minimized_control_bar_title",
                                "PACKAGE": "com.android.car.media"
                        },
                        "BACK_BUTTON": {
                                "TYPE": "DESCRIPTION",
                                "VALUE": "Back"
                        }
                },
                "MEDIA_CENTER_ON_HOME_SCREEN": {
                        "PLAY_PAUSE_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "play_pause_stop",
                                "PACKAGE": "com.android.car.carlauncher"
                        },
                        "NEXT_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "skip_next",
                                "PACKAGE": "com.android.car.carlauncher"
                        },
                        "PREVIOUS_BUTTON": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "skip_prev",
                                "PACKAGE": "com.android.car.carlauncher"
                        },
                        "TRACK_NAME": {
                                "TYPE": "RESOURCE_ID",
                                "VALUE": "title",
                                "PACKAGE": "com.android.car.carlauncher"
                        }
                }
        }
}
  

Configuraciones alternativas del dispositivo

En la siguiente muestra de código, se muestra un ejemplo del archivo de configuración JSON en el que la configuración predeterminada se anula con la configuración del DUT. En este ejemplo:

  • En los dispositivos de referencia, la configuración de Internet se denomina Internet y redes, y en el DUT, Conectividad.

  • La configuración de fecha y hora está disponible en Configuración > Fecha y hora para los dispositivos de referencia y en Configuración > Sistema > Fecha y hora para el DUT.

// Default configuration file
{
    ....
    "SECURITY_SETTINGS_SCROLL_ELEMENT": {
      "TYPE": "RESOURCE_ID",
      "VALUE": "fragment_container",
    },
    ....
}

// JSON configuration file for non-reference device
{
    ....
    "SECURITY_SETTINGS_SCROLL_ELEMENT": {
      "TYPE": "RESOURCE_ID",
      "VALUE": "car_ui_recycler_view"
    },
    ....
}

Cuando el archivo de configuración JSON está listo, se proporciona en el tiempo de ejecución, como se muestra en el siguiente bloque de código:

# Push The JSON configuration file to the device
adb -s DEVICE-SERIAL push PATH-OF-JSON-FILE /data/local/tmp/runtimeSpectatioConfig.json

En este comando:

  • DEVICE-SERIAL: ID de serie del DUT. Este parámetro no es obligatorio si solo un dispositivo está conectado al host.

  • PATH-TO-JSON-FILE: Es la ruta de acceso al archivo JSON en la máquina host.

Formato de configuración

Hay cinco objetos de nivel superior en la configuración, con las siguientes claves y valores:

Objeto Descripción
PACKAGES Objeto que describe el paquete principal de varias apps, que se usa para determinar cuándo una app está en primer plano.
ACTIONS Es un objeto que indica los tipos de acción y los parámetros para varias acciones. Por ejemplo, si quieres usar botones o un gesto para desplazarte.
COMMANDS Es un objeto que especifica comandos que realizan varias acciones.
UI_ELEMENTS Es un objeto que se usa para construir objetos `BySelectors` de UI Automator que seleccionan elementos de IU (se describen en detalle a continuación).
WORKFLOWS Secuencias de acciones que completan tareas de alto nivel (se describen en detalle a continuación).

Elementos de la IU

Cada elemento de la IU tiene un TYPE que especifica lo que buscará UI Automator para identificar el elemento (como el ID de recurso, el texto y la descripción) y los valores de configuración asociados a ese tipo. En general, cada vez que un asistente identifica un elemento en la pantalla con esta configuración, obtiene exactamente un elemento. Si varios elementos coinciden con la configuración, se usará uno arbitrario en la prueba. Por lo tanto, la configuración debe escribirse (en general) de forma lo suficientemente específica como para reducirse a un solo elemento en el contexto pertinente.

TEXTO

Este es el tipo de elemento de IU más simple. El elemento de IU se identifica por su texto y requiere una coincidencia exacta.

    "CALL_HISTORY_MENU": {
      "TYPE": "TEXT",
      "VALUE": "Recents"
    }

TEXT_CONTAINS

Es igual que TEXT, excepto que el VALUE especificado solo debe aparecer en algún lugar del texto del elemento que se debe hacer coincidir.

    "PRIVACY_CALENDAR": {
      "TYPE": "TEXT_CONTAINS",
      "VALUE": "Calendar"
    }

DESCRIPCIÓN

Identifica el elemento por su atributo de descripción del contenido, lo que requiere una coincidencia exacta.

    "APP_GRID_SCROLL_BACKWARD_BUTTON": {
      "TYPE": "DESCRIPTION",
      "VALUE": "Scroll up"
    }

RESOURCE_ID

Identifica el elemento por su ID de recurso y, de manera opcional, también verifica el componente de paquete de ese ID. La clave PACKAGE es opcional. Si se omite, coincidirá cualquier paquete y solo se tendrá en cuenta la parte del ID que sigue a :id/.

    "APP_LIST_SCROLL_ELEMENT": {
      "TYPE": "RESOURCE_ID",
      "VALUE": "apps_grid",
      "PACKAGE": "com.android.car.carlauncher"
    }

SE PUEDE HACER CLIC Y DESPLAZAR

Identifica el elemento según si se puede hacer clic en él o desplazarse por él. Estos son tipos de elementos muy amplios y, por lo general, solo se deben usar en un MULTIPLE para ayudar a reducir otro tipo de elemento. La clave FLAG es opcional y, de forma predeterminada, se establece en true.

    "SAMPLE_ELEMENT": {
      "TYPE": "CLICKABLE",
      "FLAG": false
    }

CLASE

Identifica el elemento según su clase.

    "SECURITY_SETTINGS_ENTER_PASSWORD": {
      "TYPE": "CLASS",
      "VALUE": "android.widget.EditText"
    }

HAS_ANCESTOR

Identifica el elemento buscando la jerarquía de widgets en sus elementos superiores. La clave ANCESTOR contiene un objeto que identifica al principal. La clave DEPTH especifica qué tan arriba en la jerarquía se debe buscar. DEPTH es opcional y tiene un valor predeterminado de 1.

      "SAMPLE_ELEMENT": {
      "TYPE": "HAS_ANCESTOR",
      "DEPTH": 2,
      "ANCESTOR": {
        "TYPE": "CLASS",
        "VALUE": "android.view.ViewGroup"
      }
    }

HAS_DESCENDANT

Identifica el elemento mirando hacia abajo en la jerarquía a sus elementos secundarios. La clave DESCENDANT contiene un objeto que especifica el elemento secundario que se debe buscar. La clave DEPTH especifica qué tan arriba en la jerarquía se debe buscar. DEPTH es opcional y tiene un valor predeterminado de 1.

      "SAMPLE_ELEMENT": {
      "TYPE": "HAS_DESCENDANT",
      "DEPTH": 2,
      "DESCENDANT": {
        "TYPE": "CLASS",
        "VALUE": "android.view.ViewGroup"
      }
    }

MÚLTIPLE

Identifica el elemento en función de varias condiciones simultáneas, todas las cuales deben cumplirse.

      "APP_INFO_SETTINGS_PERMISSION_MANAGER": {
      "TYPE": "MULTIPLE",
      "SPECIFIERS": [
        {
          "TYPE": "CLASS",
          "VALUE": "android.widget.RelativeLayout"
        },
        {
          "TYPE": "HAS_DESCENDANT",
          "MAX_DEPTH": 2,
          "DESCENDANT": {
            "TYPE": "TEXT",
            "VALUE": "Permission manager"
          }
        }
      ]
    }

En este ejemplo, la configuración identifica un RelativeLayout que tiene un elemento secundario en la profundidad 2, que tiene el texto Permission manager.

Workflows

Un flujo de trabajo representa una secuencia de acciones que se usan para completar una tarea en particular, que puede diferir lo suficiente entre los distintos tipos de dispositivos y es más flexible de representar en la configuración que en el código.

    "WORKFLOWS": {
    "OPEN_SOUND_SETTINGS_WORKFLOW": [
      {
        "NAME": "Go to Home",
        "TYPE": "PRESS",
        "CONFIG": {
          "TEXT": "HOME"
        }
      },
      {
        "NAME": "Open Settings",
        "TYPE": "COMMAND",
        "CONFIG": {
          "TEXT": "am start -a android.settings.SETTINGS"
        }
      },
      {
        "NAME": "Open Sound Settings",
        "TYPE": "SCROLL_TO_FIND_AND_CLICK",
        "CONFIG": {
          "UI_ELEMENT": {
            "TYPE": "TEXT",
            "VALUE": "Sound"
          }
        },
        "SCROLL_CONFIG": {
          "SCROLL_ACTION": "USE_GESTURE",
          "SCROLL_DIRECTION": "VERTICAL",
          "SCROLL_ELEMENT": {
            "TYPE": "RESOURCE_ID",
            "VALUE": "car_ui_recycler_view"
          }
        }
      }
    ]
  }

Cada flujo de trabajo es un par clave-valor en el que la clave es el nombre del flujo de trabajo y el valor es un array de acciones que se deben realizar. Cada acción tiene un NAME, un TYPE, (por lo general) un CONFIG y (a veces) un SWIPE_CONFIG o un SCROLL_CONFIG. Para la mayoría de los TYPE, CONFIG es un objeto con una clave UI_ELEMENT cuyo valor adopta la misma forma que una entrada de elemento de IU (consulta más arriba). Estos son los tipos:

PRESS
LONG_PRESS
CLICK
LONG_CLICK
CLICK_IF_EXIST
HAS_UI_ELEMENT_IN_FOREGROUND
SCROLL_TO_FIND_AND_CLICK
SCROLL_TO_FIND_AND_CLICK_IF_EXIST
SWIPE_TO_FIND_AND_CLICK
SWIPE_TO_FIND_AND_CLICK_IF_EXIST

Para los otros TYPEs, los detalles de configuración son los siguientes:

Objeto Descripción
COMMAND Objeto con un valor TEXT que contiene el comando que se ejecutará.
HAS_PACKAGE_IN_FOREGROUND Objeto con un valor TEXT que contiene el paquete.
SWIPE Omite CONFIG key para una acción SWIPE. Esto solo usa SWIPE_CONFIG.
WAIT_MS Objeto con un valor TEXT que contiene la cantidad de milisegundos que se deben esperar.

Las acciones relacionadas con el desplazamiento y el deslizamiento requieren una configuración adicional, como se indica a continuación:

SCROLL_CONFIG

Objeto Descripción
SCROLL_ACTION USE_GESTURE o USE_BUTTON
SCROLL_DIRECTION HORIZONTAL o VERTICAL
SCROLL_ELEMENT Objeto que indica el contenedor al que se debe desplazar, con el mismo formato que una configuración de elemento de IU (consulta más arriba).
SCROLL_FORWARD, SCROLL_BACKWARD Los botones de desplazamiento hacia adelante y hacia atrás (obligatorios cuando SCROLL_ACTION es USE_BUTTON).
SCROLL_MARGIN Si SCROLL_ACTION es USE_GESTURE, es la distancia desde el borde del contenedor para iniciar y detener el arrastre que se usará para realizar el desplazamiento (opcional, valor predeterminado = 10).
SCROLL_WAIT_TIME Si SCROLL_ACTION es USE_GESTURE, es el tiempo en milisegundos que se espera entre los gestos de desplazamiento cuando se busca un objeto para hacer clic. (Opcional, valor predeterminado = 1).

SWIPE_CONFIG

Objeto Descripción
SWIPE_DIRECTION Puede ser TOP_TO_BOTTOM, BOTTOM_TO_TOP, LEFT_TO_RIGHT o RIGHT_TO_LEFT.
SWIPE_FRACTION

Una de las siguientes opciones:

  • FULL: Gesto de deslizamiento desde un borde de la pantalla hasta el otro

    O BIEN
  • DEFAULT: De borde a borde de la pantalla, con un búfer de cinco (5) píxeles en cada lado.

    O
  • THREE_QUARTER, HALF o QUARTER: El gesto de deslizamiento finaliza a cinco (5) píxeles del borde de la pantalla y comienza en el punto tal que cubre la distancia indicada de la pantalla.
NUMBER_OF_STEPS Cantidad de pasos que se usarán para realizar el deslizamiento. Consulta los segmentSteps.

Compilación y ejecución

El framework de Spectatio se compila automáticamente como parte del APK de prueba. Para compilar el APK de prueba, la base de código de AOSP debe residir en la estación de trabajo local. Después de compilar el APK de prueba, el usuario debe instalarlo en el dispositivo y ejecutar la prueba.

En el siguiente ejemplo de código, se muestra la compilación, la instalación y la ejecución de un APK de prueba.

# Build Test APK
make TEST-APK-NAME
# Install Test APK
adb -s DEVICE-SERIAL install -r PATH-FOR-BUILT-TEST-APK
# Execute Test with the JSON file
adb -s DEVICE-SERIAL shell am instrument -w -r -e debug false -e config-file-path /data/local/tmp/jsonFile.json -e class TEST-PACKAGE.TEST-CLASSNAME TEST-PACKAGE/androidx.test.runner.AndroidJUnitRunner

En estos comandos, se incluye lo siguiente:

  • TEST-APK-NAME: Es el nombre de la app que se probará. Por ejemplo, configura TEST-APK-NAME como AndroidAutomotiveSettingsTests para probar la configuración de Wi-Fi como se especifica en el archivo Android.bp. El nombre del APK se puede encontrar en el archivo Android.bp correspondiente de la prueba de Automotive.

  • DEVICE-SERIAL: ID de serie del DUT. Este parámetro no es obligatorio si solo un dispositivo está conectado al host.

  • config-file-path: Es un parámetro opcional que solo se requiere para proporcionar parámetros de configuración de la IU del dispositivo no predeterminados, como se especifica en el archivo de configuración JSON. Si no se proporciona, el framework usa valores predeterminados para ejecutar las pruebas.

  • PATH-FOR-BUILT-TEST-APK: Es la ruta en la que se compila el APK de prueba cuando se ejecuta el comando make.

  • TEST-PACKAGE: Es el nombre del paquete de prueba.

  • TEST-CLASSNAME: Es el nombre de la clase de prueba. Por ejemplo, para la prueba Configuración de Wi-Fi, el paquete de prueba es android.platform.tests y el nombre de la clase de prueba es WifiSettingTest.

Biblioteca de fragmentos de Automotive

La Biblioteca de fragmentos de Automotive es un conjunto de bibliotecas de pruebas de Android para el Proyecto de código abierto de Android (AOSP) diseñadas para interactuar con apps y servicios automotrices. Aprovecha Spectatio con un mecanismo conveniente para ejecutar llamadas de procedimiento remoto (RPC) desde una máquina host (de prueba) a un dispositivo con Android.

Comenzar

Antes de comenzar, revisa estas secciones.

Requisitos previos

  • Python 3.x instalado en la máquina host
  • Configuración del entorno de AOSP con las herramientas de compilación necesarias
  • Un dispositivo Android Automotive (emulador o dispositivo físico) con acceso a adb

Compilación

Para compilar los distintos fragmentos que proporciona la biblioteca de fragmentos de Automotive, puedes usar el archivo android.bp proporcionado. Sigue los comandos de la sección anterior para compilar el APK.

Implementación

Después de compilar correctamente las bibliotecas de fragmentos, implementa los APKs resultantes en el dispositivo de destino con el comando adb install que se mencionó en la sección anterior.

Cómo ejecutar pruebas

Las bibliotecas de fragmentos exponen varios métodos de RPC para interactuar con el sistema automotriz. Estos métodos se pueden invocar a través del framework de Mobly desde la máquina host. Si suponemos que tienes configurado el entorno de prueba de Mobly, puedes usar la secuencia de comandos snippet_shell.py para abrir una shell interactiva de Python, en la que puedes invocar manualmente métodos de RPC en el dispositivo. Ejemplo de invocación:

python3 snippet_shell.py com.google.android.mobly.snippet.bundled -s <serial>

Reemplaza <serial> por el número de serie del dispositivo, que puedes obtener con adb devices si hay varios dispositivos conectados.

Bibliotecas incluidas

La biblioteca de fragmentos de Automotive incluye las siguientes bibliotecas de fragmentos y asistentes:

  • AutomotiveSnippet: Proporciona APIs relacionadas con las operaciones del vehículo, como marcar, controlar el volumen, usar las teclas físicas del vehículo y la interacción con el centro multimedia.

  • PhoneSnippet: Proporciona APIs relacionadas con la telefonía, como el control de llamadas, la navegación por los contactos y las operaciones de SMS.

El fragmento de Automotive y el fragmento de PhoneSnippet comparten cierta lógica común. Específicamente, puedes invadir llamadas de RCP relacionadas con Bluetooth para vincular un dispositivo automotriz y un teléfono. En este bt_discovery_test, se muestra cómo hacerlo.