Spectatio: framework de prueba para Automotive

Spectatio es un framework de pruebas 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 del AAOS y sus apps.

Diseño de alto nivel

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

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

Framework de Spectatio con diseño de alto nivel

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

Compilado a partir de UI Automator, el framework de Spectatio 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 las hace independientes del dispositivo en prueba (DUT) y escalables para probar varios dispositivos, si se admite.

La Figura 1 muestra que el framework de Spectatio está modularizado en función de apps de referencia, como Dialer, Medicenter y Configuración, con interfaces y ayudantes específicos de la app, lo que permite que se extienda fácilmente a apps nuevas. El framework de Spectatio reutiliza las clases auxiliares estándar y de utilidad comunes. La clase auxiliar estándar es la clase superior de todas las funciones auxiliares de la app y proporciona funciones estándar que son específicas del dispositivo o aplicables a 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 ayudantes específicos de la app, mientras extiende la clase de ayuda estándar existente y, además, importa las clases de ayuda 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 ayuda de la app proporciona un plano para la implementación de un asistente de apps. Consiste en varias funciones auxiliares que se necesitan para probar apps. Cada app tiene su propia interfaz, como IAutoSettingHelper y IAutoDialHelper. Para obtener más información y una lista de funciones de la interfaz, consulta las funciones de la interfaz de la app helper 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 auxiliar estándar se define en AbstractAutoStandardAppHelper.java.

El framework usa las clases de ayuda de utilidad. Por ejemplo, AutoJsonUtility.java es una clase de utilidad que carga el archivo de configuración JSON del dispositivo determinado y actualiza las configuraciones del framework durante el tiempo de ejecución.

El módulo de implementación auxiliar de la app 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 automotriz. Cada app tiene su propia implementación, como SettingHelperImpl y DialHelperImpl, que las pruebas de Automotive usan para probar las apps. Para obtener más información y una lista de implementaciones, consulta las funciones de implementación de ayudantes de apps en AOSP.

Las pruebas de Automotive usan las funciones de implementación de la app auxiliar para probar varias operaciones relacionadas con la app. Usa la clase HelperAccessor para obtener acceso a las funciones de implementación de la app auxiliar.

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

@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 es escalable para probar dispositivos con varias IUs y hardware. Para lograr esta escalabilidad, Spectatio usa configuraciones de dispositivos predeterminadas basadas en el dispositivo de referencia. Para admitir configuraciones de dispositivos que no son predeterminadas, el framework usa un archivo de configuración JSON durante el tiempo de ejecución para establecer los cambios de IU deseados para el 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 debe contener solo la información sobre los cambios de la IU para el DUT. El resto de los elementos de la IU usan los valores de configuración predeterminados proporcionados en el framework.

Configuraciones predeterminadas del dispositivo

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

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

    {
        "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 de dispositivos alternativas

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:

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

  • 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 proporcionará 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: Es el 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 anfitrión.

Formato de configuración

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

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

Elementos de la IU

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

TEXTO

Este es el tipo de elemento de IU más simple. El elemento de la 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 de contenido, 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, opcionalmente, también puedes verificar el componente del paquete de ese ID. La clave PACKAGE es opcional. Si se omite, coincidirá cualquier paquete y solo se considerará la parte del ID que sigue a :id/.

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

HACER CLIC, DESPLAZABLE

Identifica el elemento según si se puede hacer clic en él (o no) o si se puede desplazar. 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 se establece de forma predeterminada 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

Para identificar el elemento, busca la jerarquía de widgets en sus ancestros. La clave ANCESTOR contiene un objeto que identifica al ancestro. La clave DEPTH especifica hasta dónde se debe buscar en la jerarquía. 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

Para identificar el elemento, busca en la jerarquía sus elementos secundarios. La clave DESCENDANT contiene un objeto que especifica el elemento secundario que se debe buscar. La clave DEPTH especifica hasta dónde se debe buscar en la jerarquía. DEPTH es opcional y tiene un valor predeterminado de 1.

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

VARIOS

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

      "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 descendiente en la profundidad 2, que tiene el texto Permission manager.

Workflows

Un flujo de trabajo representa una secuencia de acciones que se usan para realizar una tarea particular, que puede diferir bastante de un tipo de dispositivo a otro y es más flexible para representarse 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 para realizar. Cada acción tiene un NAME, un TYPE, (por lo general) un CONFIG y (a veces) un SWIPE_CONFIG o SCROLL_CONFIG. Para la mayoría de los TIPOS, CONFIG es un objeto con una clave UI_ELEMENT cuyo valor toma la misma forma que una entrada de elemento de la IU (consulta la sección anterior). Esos TYPE son los siguientes:

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 TYPE, los detalles de configuración son los siguientes:

Objeto Descripción
COMMAND Un objeto con un valor TEXT que contiene el comando que se ejecutará.
HAS_PACKAGE_IN_FOREGROUND Un objeto con un valor TEXT que contiene el paquete.
SWIPE Omite CONFIG key para una acción SWIPE. Esta opción solo usa SWIPE_CONFIG
WAIT_MS Un 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:

DESPLAZAMIENTO_CONFIGURACIÓN

Objeto Descripción
SCROLL_ACTION USE_GESTURE o USE_BUTTON
SCROLL_DIRECTION HORIZONTAL o VERTICAL
SCROLL_ELEMENT Un objeto que indica el contenedor que se debe desplazar, con el mismo formato que la configuración de un elemento de la 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, 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 en el que hacer clic. (Opcional, valor predeterminado = 1).

SWIPE_CONFIGURA

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

Una de las siguientes opciones:

  • FULL: Gesto de deslizamiento de un borde de la pantalla al otro

    O
  • 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 de modo que cubra la distancia indicada de la pantalla.
NUMBER_OF_STEPS Es la cantidad de pasos que se usarán para realizar el deslizamiento. Consulta los segmentSteps.

Compila y ejecuta

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 la siguiente muestra 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:

  • TEST-APK-NAME: Es el nombre de la app que se probará. Por ejemplo, establece TEST-APK-NAME en 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 respectivo para la prueba de Automotive.

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

  • config-file-path: Es un parámetro opcional que solo se requiere para proporcionar configuraciones de IU del dispositivo no predeterminadas, 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 de acceso 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 de 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 con el objetivo de interactuar con apps y servicios de vehículos. 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 diversos fragmentos que proporciona la biblioteca de fragmentos de Automotive, puedes usar el archivo android.bp proporcionado. Los siguientes comandos de la sección anterior para compilar el APK

Implementación

Después de compilar correctamente las bibliotecas de fragmentos, implementa los APK 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 anfitrión. Si 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 dispositivos adb si hay varios dispositivos conectados.

Bibliotecas incluidas

La Biblioteca de fragmentos de Automotive incluye los siguientes ayudantes y bibliotecas de fragmentos:

  • AutomotiveSnippet: Proporciona APIs relacionadas con las operaciones del vehículo, como la marcación, el control de volumen, las teclas duras del vehículo y la interacción con el centro multimedia.

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

El fragmento de Automotive y el Phonesnippet comparten una lógica en común. Específicamente, puedes invadir las 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.