Spectatio: מסגרת בדיקה לרכב

Spectatio היא מסגרת בדיקה בקוד פתוח שפותחה לבדיקה של Android Automotive OS‏ (AAOS) במכשירים אמיתיים וווירטואליים. Spectatio מספק ממשקי API לבדיקת אפליקציות במכשיר לרכב. זהו פתרון שניתן להרחבה ולתאימות, המשמש לאימות היכולות והביצועים של AAOS והאפליקציות שלו.

העיצוב הכללי

אפשר להתאים את המסגרת של Spectatio ולהרחיב אותה להטמעות שונות של ממשק המשתמש של AAOS. הוא משמש לבדיקת היכולות והביצועים של AAOS בחומרה של המכשיר, במהדמנים ובסביבות וירטואליות.

בתרשים הבא מוסבר העיצוב הכללי של מסגרת Spectatio.

העיצוב הכללי של מסגרת Spectatio

איור 1. העיצוב הכללי של מסגרת Spectatio.

מסגרת Spectatio, שנבנתה על גבי UI Automator, מספקת קבוצה של ממשקי API ליצירת בדיקות ממשק משתמש שמקיימות אינטראקציה עם אפליקציות של משתמשים ושל מערכות ב-AAOS. בבדיקות הרכב נעשה שימוש בממשקי ה-API שסופקו על ידי מסגרת Spectatio לצורך בדיקה. כך הבדיקות האלה עצמאיות מהמכשיר שנבדק (DUT) וניתן להתאים אותן לבדיקה של מכשירים שונים, אם הם נתמכים.

באיור 1 אפשר לראות ש-Spectatio הוא מסגרת מודולרית שמבוססת על אפליקציות עזר כמו Dialer‏, Medicenter והגדרות, באמצעות ממשקים ורכיבי עזר ספציפיים לאפליקציות. כך אפשר להרחיב אותו בקלות לאפליקציות חדשות. המסגרת של Spectatio משתמשת שוב בסטנדרטים הנפוצים ובכיתות העזר של התשתית. כיתת העזר הרגילה היא הכיתה ההורה של כל פונקציות העזר של האפליקציה, והיא מספקת פונקציות רגילות ספציפיות למכשיר או פונקציות שחלות על אפליקציות שונות. כיתות העזר של השירותים מספקות שירותים כמו קריאה או כתיבת קבצים מהמכשיר.

ארכיטקטורה

כדי לספק קבוצה של ממשקי API ליצירת בדיקות של ממשק המשתמש, מסגרת Spectatio מטמיעה ממשקים ועוזרנים ספציפיים לאפליקציה, תוך הרחבת סוג העוזרן הסטנדרטי הקיים וייבוא של סוגים של עוזרני שירות.

באיור 2 מוצגת הארכיטקטורה ברמה גבוהה של מסגרת Spectatio וכל הישויות שמעורבות בהטמעת ממשקי API לבדיקה של אפליקציה.

ארכיטקטורה ברמה גבוהה של מסגרת Spectatio

איור 2. הארכיטקטורה ברמה גבוהה של מסגרת Spectatio.

ממשק ה-App Helper מספק תוכנית להטמעה של App Helper. הוא מורכב מפונקציות עזר שונות שנדרשות לבדיקת אפליקציות. לכל אפליקציה יש ממשק משלה, כמו IAutoSettingHelper ו-IAutoDialHelper. מידע נוסף ורשימת פונקציות ממשק זמינים במאמר פונקציות ממשק של כלי עזר לאפליקציות ב-AOSP.

סיווג העזרה הרגיל מורכב ממאפיינים ופונקציות רגילים שנדרשים להגדרת המכשיר, אבל הם לא ספציפיים לאף אפליקציה, כמו pressHome ו-scroll. כיתה העזר הרגילה מוגדרת ב-AbstractAutoStandardAppHelper.java.

המסגרת משתמשת בכיתות העזר של התשתית. לדוגמה, AutoJsonUtility.java הוא סוג שירות לטעינת קובץ התצורה של המכשיר בפורמט JSON ועדכון הגדרות המסגרת בזמן הריצה.

מודול הטמעת העזרה לאפליקציה הוא הליבה של מסגרת Spectatio. הוא מכיל את ההטמעה של פונקציות העזר שמוגדרות בממשק העזר של האפליקציה, שנדרשות לבדיקה של אפליקציות במכשיר לכלי רכב. לכל אפליקציה יש הטמעה משלה, כמו SettingHelperImpl ו-DialHelperImpl, שבהן נעשה שימוש בבדיקות הרכב לצורך בדיקת האפליקציות. למידע נוסף ורשימת הטמעות, ראו פונקציות להטמעת כלי עזר לאפליקציות ב-AOSP.

בבדיקות לכלי רכב נעשה שימוש בפונקציות ההטמעה של ה-App Helper כדי לבדוק פעולות שונות שקשורות לאפליקציה. כדי לקבל גישה לפונקציות ההטמעה של ה-App Helper, משתמשים בכיתה HelperAccessor.

בקוד הבא מוצגים ההגדרה, הניקוי וההרצה של בדיקה לדוגמה של כלי רכב.

@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());
  }
}

התאמה אישית

המסגרת של Spectatio לא תלויה בממשק המשתמש של המכשיר, כך שאפשר להתאים אותה למכשירים עם ממשקי משתמש וחומרה שונים. כדי לאפשר את יכולת ההתאמה לעומס, מערכת Spectatio משתמשת בהגדרות ברירת המחדל של המכשיר על סמך מכשיר העזר. כדי לתמוך בהגדרות מכשיר שאינן ברירת המחדל, המסגרת משתמשת בקובץ תצורה של JSON בזמן הריצה כדי להגדיר את השינויים הרצויים בממשק המשתמש של המכשיר. קובץ תצורה בפורמט JSON תומך ברכיבי ממשק משתמש כמו TEXT, ‏ DESCRIPTION ו-RESOURCE_ID, יחד עם הגדרות path, והוא חייב להכיל רק את המידע על השינויים בממשק המשתמש של ה-DUT. שאר רכיבי ממשק המשתמש משתמשים בערכי ברירת המחדל של ההגדרות שסופקו במסגרת.

הגדרות ברירת המחדל של המכשיר

קובץ התצורה לדוגמה בפורמט JSON מציג את הגדרות המכשיר הזמינות ואת ערכי ברירת המחדל שלהן.

לחצו כאן כדי להציג קובץ תצורה לדוגמה בפורמט JSON

    {
        "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"
                        }
                }
        }
}
  

הגדרות חלופיות של המכשיר

קוד לדוגמה שמציג קובץ תצורה של JSON, שבו הגדרות ברירת המחדל מקבלות עדיפות על פני ההגדרות ב-DUT. בדוגמה הזו:

  • הגדרות האינטרנט נקראות רשת ואינטרנט במכשירי העזר וקישוריות ב-DUT.

  • הגדרות התאריך והשעה זמינות בקטע הגדרות > תאריך ושעה במכשירי העזרה, ובקטע הגדרות > מערכת > תאריך ושעה ב-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"
    },
    ....
}

כשקובץ התצורה בפורמט JSON מוכן, הוא מסופק במהלך זמן הריצה, כפי שמוצג בבלוק הקוד הבא:

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

בפקודה הזו:

  • DEVICE-SERIAL: המזהה הסידורי של ה-DUT. הפרמטר הזה לא נדרש אם רק מכשיר אחד מחובר למארח.

  • PATH-TO-JSON-FILE: הנתיב של קובץ ה-JSON במכונה המארחת.

פורמט ההגדרות האישיות

בתצורה יש חמישה אובייקטים ברמה העליונה, עם המפתחות והערכים הבאים:

אובייקט תיאור
PACKAGES אובייקט שמתאר את החבילה הראשית של אפליקציות שונות, שמשמשות לקביעת המצב שבו האפליקציה הזו נמצאת בחזית.
ACTIONS אובייקט שמציין סוגי פעולות ופרמטרים של פעולות שונות. לדוגמה, אם להשתמש בלחצנים או בתנועה כדי לגלול.
COMMANDS אובייקט שמציין פקודות שמבצעות פעולות שונות.
UI_ELEMENTS אובייקט שמשמש ליצירת 'BySelectors' של UI Automator שבוחרים רכיבי UI (מתוארים בפירוט בהמשך).
WORKFLOWS רצפי פעולות שמבצעים משימות ברמה גבוהה (מתוארים בפירוט בהמשך).

רכיבים בממשק המשתמש

לכל רכיב בממשק המשתמש יש TYPE שמציין את מה ש-UI Automator יחפש כדי לזהות את הרכיב (למשל, מזהה המשאב, הטקסט והתיאור) ואת ערכי התצורה שמשויכים לסוג הזה. באופן כללי, בכל פעם שרכיב עזר מזהה רכיב במסך באמצעות ההגדרה הזו, הוא מקבל בדיוק רכיב אחד. אם יש כמה רכיבים שתואמים להגדרה, המערכת תשתמש באחד מהם באופן שרירותי. לכן, ההגדרה צריכה (בדרך כלל) להיות ספציפית מספיק כדי לצמצם אותה לרכיב אחד בהקשר הרלוונטי.

טקסט

זהו סוג הרכיב הפשוט ביותר בממשק המשתמש. אלמנט ממשק המשתמש מזוהה לפי הטקסט שלו, והוא מחייב התאמה מדויקת.

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

TEXT_CONTAINS

זהה ל-TEXT, מלבד העובדה ש-VALUE שצוין צריך להופיע רק במקום כלשהו בטקסט של הרכיב שרוצים להתאים.

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

תיאור

מזהים את הרכיב לפי מאפיין תיאור התוכן שלו, תוך דרישה להתאמה מדויקת.

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

RESOURCE_ID

מזהים את הרכיב לפי מזהה המשאב שלו, ואפשר גם לבדוק את רכיב החבילה של המזהה הזה. המפתח PACKAGE הוא אופציונלי. אם לא מציינים אותו, כל חבילת קוד תתאים, וייבוא הנתונים יתבצע רק לגבי החלק של המזהה שמופיע אחרי :id/.

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

ניתנים ללחיצה ולגלילה

מזהים את האלמנט על סמך האפשרות ללחוץ עליו (או לא) או לגלול בו. אלה סוגים רחבים מאוד של רכיבים, ובדרך כלל צריך להשתמש בהם רק ב-MULTIPLE כדי לצמצם את הסוג של רכיב אחר. המפתח FLAG הוא אופציונלי, והברירת המחדל שלו היא true.

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

CLASS

מזהים את הרכיב על סמך הכיתה שלו.

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

HAS_ANCESTOR

כדי לזהות את הרכיב, מחפשים את היררכיית הווידג'ט אצל אביו. המפתח ANCESTOR מכיל אובייקט שמזהה את האב. המפתח DEPTH מציין עד כמה גבוה בהיררכיה צריך לחפש. השדה DEPTH הוא אופציונלי וערך ברירת המחדל שלו הוא 1.

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

HAS_DESCENDANT

כדי לזהות את הרכיב, בודקים את הצאצאים שלו בהיררכיה. המפתח DESCENDANT מכיל אובייקט שמציין את הצאצא שרוצים לחפש. המפתח DEPTH מציין עד כמה גבוה בתוך ההיררכיה צריך לחפש. השדה DEPTH הוא אופציונלי וערך ברירת המחדל שלו הוא 1.

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

MULTIPLE

זיהוי הרכיב על סמך מספר תנאים בו-זמנית, שכל אחד מהם חייב להתקיים.

      "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"
          }
        }
      ]
    }

בדוגמה הזו, ההגדרה מזהה RelativeLayout שיש לו צאצא בעומק 2, עם הטקסט Permission manager.

Workflows

תהליך עבודה מייצג רצף של פעולות שמשמשות לביצוע משימה מסוימת, והוא עשוי להיות שונה באופן משמעותי בהתאם לסוג המכשיר. קל יותר לייצג תהליך עבודה בהגדרה מאשר בקוד.

    "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"
          }
        }
      }
    ]
  }

כל תהליך עבודה הוא צמד מפתח/ערך, שבו המפתח הוא שם תהליך העבודה והערך הוא מערך של פעולות לביצוע. לכל פעולה יש NAME, TYPE, (בדרך כלל) CONFIG ו (לפעמים) SWIPE_CONFIG או SCROLL_CONFIG. ברוב סוגי ה-TYPE, הערך של CONFIG הוא אובייקט עם מפתח UI_ELEMENT שהערך שלו זהה לפורמט של רשומה של רכיב ממשק משתמש (ראו למעלה). סוגי ה-TYPE האלה הם:

לחיצה
לחיצה ארוכה
קליק
קליק ארוך
קליק אם קיים
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

בשאר הערכים של TYPE, פרטי ההגדרה הם:

אובייקט תיאור
COMMAND אובייקט עם ערך TEXT שמכיל את הפקודה לביצוע.
HAS_PACKAGE_IN_FOREGROUND אובייקט עם ערך TEXT שמכיל את החבילה.
SWIPE משמיטים את CONFIG key עבור פעולת SWIPE. הקוד הזה משתמש רק ב-SWIPE_CONFIG
WAIT_MS אובייקט עם ערך TEXT שמכיל את מספר אלפיות השנייה שצריך להמתין.

כדי לבצע פעולות שקשורות לגלילה ולהחלקה, צריך לקבוע הגדרות נוספות באופן הבא:

SCROLL_CONFIG

אובייקט תיאור
SCROLL_ACTION USE_GESTURE או USE_BUTTON
SCROLL_DIRECTION HORIZONTAL או VERTICAL
SCROLL_ELEMENT אובייקט שמציין את המאגר שרוצים לגלול, באותו פורמט של הגדרת רכיב בממשק המשתמש (ראו למעלה).
SCROLL_FORWARD, SCROLL_BACKWARD לחצני הגלילה קדימה ואחורה (נדרשים כש-SCROLL_ACTION הוא USE_BUTTON).
SCROLL_MARGIN אם הערך של SCROLL_ACTION הוא USE_GESTURE, המרחק ממרכז המאגר שבו מתחילים ומפסיקים את הגרירה שתשמש לביצוע הגלילה (אופציונלי, ברירת המחדל = 10).
SCROLL_WAIT_TIME אם הערך של SCROLL_ACTION הוא USE_GESTURE, זהו משך הזמן באלפיות שנייה שצריך להמתין בין תנועות הגלילה כשמחפשים אובייקט ללחוץ עליו. (אופציונלי, ברירת המחדל = 1).

SWIPE_CONFIG

אובייקט תיאור
SWIPE_DIRECTION TOP_TO_BOTTOM,‏ BOTTOM_TO_TOP,‏ LEFT_TO_RIGHT או RIGHT_TO_LEFT
SWIPE_FRACTION

אחת מהאפשרויות הבאות:

  • FULL: מחליקים מהקצה האחד של המסך לקצה השני

    לחלופין,
  • DEFAULT: מקצה המסך לקצה המסך, עם מאגר של חמישה (5) פיקסלים בכל צד.

    OR
  • THREE_QUARTER,‏ HALF או QUARTER: תנועת ההחלקה מסתיימת חמישה (5) פיקסלים ממרכז המסך, ומתחילה בנקודה שמכסה את המרחק שצוין במסך.
NUMBER_OF_STEPS מספר השלבים לביצוע החלקה. פרטים נוספים זמינים ב segmentSteps.

פיתוח והרצה

ה-framework של Spectatio נוצר באופן אוטומטי כחלק מ-APK הבדיקה. כדי ליצור את קובץ ה-APK לבדיקה, קוד המקור של AOSP צריך להיות בתחנת העבודה המקומית. אחרי יצירת קובץ ה-APK לבדיקה, המשתמש צריך להתקין את קובץ ה-APK במכשיר ולהריץ את הבדיקה.

בדוגמת הקוד הבאה מוצגים השלבים של יצירת גרסת build, ההתקנה וההפעלה של קובץ APK לבדיקה.

# 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

בפקודות האלה:

  • TEST-APK-NAME: השם של האפליקציה שרוצים לבדוק. לדוגמה, מגדירים את TEST-APK-NAME כ-AndroidAutomotiveSettingsTests כדי לבדוק את הגדרות ה-Wi-Fi כפי שצוינו בקובץ Android.bp. שם ה-APK מופיע בקובץ Android.bp המתאים של בדיקת Automotive.

  • DEVICE-SERIAL: המזהה הסידורי של ה-DUT. הפרמטר הזה לא נדרש אם רק מכשיר אחד מחובר למארח.

  • config-file-path: פרמטר אופציונלי שנדרש רק כדי לספק הגדרות של ממשק המשתמש של המכשיר שאינן ברירת המחדל, כפי שצוין בקובץ התצורה בפורמט JSON. אם לא מציינים את הפרמטרים האלה, המערכת תשתמש בערכי ברירת המחדל להרצת הבדיקות.

  • PATH-FOR-BUILT-TEST-APK: הנתיב שבו נוצר קובץ ה-APK לבדיקה כשמפעילים את הפקודה make.

  • TEST-PACKAGE: השם של חבילת הבדיקה.

  • TEST-CLASSNAME: השם של מחלקת הבדיקה. לדוגמה, בבדיקה Wifi Settings, שם החבילה הוא android.platform.tests ושם הכיתה של הבדיקה הוא WifiSettingTest.

ספריית קטעי מידע על רכבים

ספריית Automotive Snippet היא קבוצה של ספריות בדיקה של Android לפרויקט Android Open Source Project‏ (AOSP), שנועדו לתקשר עם אפליקציות ושירותים לכלי רכב. הוא משתמש ב-Spectatio עם מנגנון נוח להפעלת קריאות לפרוצדורות מרוחקות (RPC) ממכונת מארח (בדיקה) למכשיר מבוסס-Android.

שנתחיל?

לפני שמתחילים, כדאי לעיין בקטעים הבאים.

דרישות מוקדמות

  • Python 3.x מותקן במכונה המארחת.
  • הגדרת סביבה של AOSP עם כלי ה-build הנדרשים.
  • מכשיר Android לכלי רכב (מכונה וירטואלית או מכשיר פיזי) עם גישה ל-adb.

קומפילציה

כדי לקמפל את קטעי הקוד השונים שסופקו על ידי ספריית הקטעים לכלי רכב, תוכלו להשתמש בקובץ android.bp שסופק. פועלים לפי הפקודות בקטע הקודם כדי לקמפל את קובץ ה-APK.

פריסה

אחרי שמאגרי ה-snippets יקובצו, אפשר לפרוס את חבילות ה-APK שנוצרו במכשיר היעד באמצעות הפקודה adb install שצוינה בקטע הקודם.

הרצת בדיקות

ספריות הקטעים חושפות כמה שיטות RPC ליצירת אינטראקציה עם מערכת הרכב. אפשר להפעיל את השיטות האלה דרך מסגרת Mobly מהמכונה המארחת. בהנחה שהגדרתם את סביבת הבדיקה של Mobly, תוכלו להשתמש בסקריפט snippet_shell.py כדי לפתוח מעטפת Python אינטראקטיבית, שבה תוכלו להפעיל באופן ידני שיטות RPC במכשיר. דוגמה להפעלה:

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

מחליפים את <serial> במספר הסידורי של המכשיר. אם יש כמה מכשירים מחוברים, אפשר לקבל את המספר באמצעות adb devices.

ספריות כלולות

ספריית הקטעים של Automotive כוללת את ספריות הקטעים ואת הספריות העזר הבאות:

  • AutomotiveSnippet: ממשקי API שקשורים לפעולות ברכב, כמו חיוג, בקרת עוצמת קול, מקשים פיזיים ברכב ואינטראקציה עם מרכז המדיה.

  • PhoneSnippet: ממשקי API שקשורים לטלפוניה, כולל טיפול בשיחות, גלישה באנשי קשר ופעולות של שליחת הודעות SMS.

לקטע הקוד לכלי רכב ולקטע הקוד PhoneSnippet יש לוגיקה משותפת מסוימת. באופן ספציפי, אפשר לפרוץ לשיחות RCP שקשורות ל-Bluetooth כדי להתאים מכשיר רכב למכשיר טלפון. bt_discovery_test מראה איך עושים את זה.