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

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

עיצוב ברמה גבוהה

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

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

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

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

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

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

ארכיטקטורה

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

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

ארכיטקטורה כללית של Spectatio framework

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

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

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

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

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

בדיקות של אפליקציות לרכב משתמשות בפונקציות של הטמעת כלי העזר לאפליקציות כדי לבדוק פעולות שונות שקשורות לאפליקציה. כדי לקבל גישה לפונקציות של הטמעת כלי העזר לאפליקציות, צריך להשתמש במחלקה 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. הוא חייב להכיל רק את המידע על השינויים בממשק המשתמש של המכשיר הנבדק. כל שאר רכיבי ממשק המשתמש משתמשים בערכי ברירת המחדל של ההגדרות שמופיעים במסגרת.

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

בקובץ ההגדרות הבא בפורמט 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 מחליפות את הגדרות ברירת המחדל. בדוגמה הזו:

  • ההגדרות של האינטרנט נקראות רשת ואינטרנט במכשירי ההשוואה וקישוריות במכשיר הנבדק.

  • הגדרות התאריך והשעה זמינות בהגדרות > תאריך ושעה במכשירי העיון ובהגדרות > מערכת > תאריך ושעה במכשיר הנבדק.

// 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 שבוחרים רכיבי ממשק משתמש (מתואר בפירוט בהמשך).
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. ברוב המקרים, CONFIG הוא אובייקט עם מפתח UI_ELEMENT שהערך שלו זהה לערך של רכיב בממשק המשתמש (ראו למעלה). הסוגים האלה הם:

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

לסוגים האחרים, פרטי ההגדרה הם:

אובייקט תיאור
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) פיקסלים בכל צד.

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

בנייה והפעלה

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

בדוגמת הקוד הבאה אפשר לראות איך יוצרים, מתקינים ומריצים קובץ 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 המתאים לבדיקה של אפליקציה לרכב.

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

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

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

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

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

מאגר קטעי מידע על רכבים

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

שנתחיל?

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

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

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

קומפילציה

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

פריסה

אחרי שמהדרים את ספריות הקטעים, פורסים את קובצי ה-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.

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