ארכיטקטורת מידע

ב-Android 8.0 הושקה ארכיטקטורת מידע חדשה לאפליקציית ההגדרות, כדי לפשט את האופן שבו ההגדרות מאורגנות ולאפשר למשתמשים למצוא במהירות את ההגדרות להתאמה אישית של מכשירי Android. ב-Android 9 הוספנו כמה שיפורים כדי לספק יותר פונקציונליות של הגדרות ולהקל על ההטמעה.

דוגמאות ומקור

רוב הדפים בהגדרות מיושמים כרגע באמצעות המסגרת החדשה. דוגמה טובה היא DisplaySettings: packages/apps/Settings/src/com/android/settings/DisplaySettings.java

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

  • CategoryKey: packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
  • DashboardFragmentRegistry: packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java
  • DashboardFragment: packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java
  • AbstractPreferenceController: frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
  • BasePreferenceController (הוצג ב-Android 9): packages/apps/Settings/src/com/android/settings/core/BasePreferenceController.java

הטמעה

מומלץ ליצרני מכשירים להתאים את ארכיטקטורת המידע הקיימת של ההגדרות ולהוסיף דפי הגדרות נוספים לפי הצורך, כדי להתאים לתכונות ספציפיות של שותפים. העברת העדפות מדף קודם (שהוטמע באמצעות SettingsPreferencePage) לדף חדש (שהוטמע באמצעות DashboardFragment) יכולה להיות מורכבת. ההעדפה מהדף הקודם כנראה לא מיושמת באמצעות PreferenceController.

לכן, כשמעבירים העדפות מדף מדור קודם לדף חדש, צריך ליצור PreferenceController ולהעביר את הקוד אל בקר לפני שמבצעים יצירה של מופע שלו ב-DashboardFragment החדש. ה-API שנדרש מפורט בשם שלו ומתועד ב-Javadoc.PreferenceController

מומלץ מאוד להוסיף בדיקת יחידה לכל PreferenceController. אם השינוי נשלח ל-AOSP, נדרשת בדיקת יחידה. מידע נוסף על כתיבת בדיקות שמבוססות על Robolectric זמין בקובץ ה-Readme packages/apps/Settings/tests/robotests/README.md.

ארכיטקטורת מידע בסגנון פלאגין

כל פריט הגדרות מיושם כהעדפה. אפשר להעביר העדפה בקלות מדף אחד לדף אחר.

כדי להקל על העברת הגדרות שונות, ב-Android 8.0 הושק פלאגין מסוג host fragment שמכיל פריטי הגדרות. פריטי ההגדרות מוגדרים כפקדים בסגנון פלאגין. לכן, דף ההגדרות מורכב מקטע מארח יחיד וממספר בקרי הגדרות.

DashboardFragment

DashboardFragment הוא המארח של בקרי העדפות בסגנון פלאגין. הקטע מקבל בירושה מ-PreferenceFragment ויש לו ווים להרחבה ולעדכון של רשימות העדפות סטטיות ורשימות העדפות דינמיות.

העדפות סטטיות

רשימת העדפות סטטית מוגדרת ב-XML באמצעות התג <Preference>. הטמעה של DashboardFragment משתמשת בשיטה getPreferenceScreenResId() כדי להגדיר איזה קובץ XML מכיל את הרשימה הסטטית של ההעדפות שיוצגו.

העדפות דינמיות

פריט דינמי מייצג משבצת עם Intent, שמובילה לפעילות חיצונית או פנימית. בדרך כלל, הכוונה מובילה לדף הגדרות אחר. לדוגמה, הפריט 'Google' בהגדרות דף הבית הוא פריט דינמי. פריטים דינמיים מוגדרים בAndroidManifest (כפי שמוסבר בהמשך) ונטענים באמצעות FeatureProvider (מוגדר כ DashboardFeatureProvider).

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

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

כדי להגדיר פעילות כהגדרה דינמית:

  • כדי לסמן את הפעילות כהגדרה דינמית, מוסיפים intent-filter לפעילות.
  • מציינים באפליקציית ההגדרות לאיזו קטגוריה היא שייכת. הקטגוריה היא קבועה, והיא מוגדרת ב-CategoryKey.
  • אופציונלי: מוסיפים טקסט סיכום כשההגדרה מוצגת.

הנה דוגמה מתוך אפליקציית ההגדרות של DisplaySettings.

<activity android:name="Settings$DisplaySettingsActivity"
                   android:label="@string/display_settings"
                   android:icon="@drawable/ic_settings_display">
             <!-- Mark the activity as a dynamic setting -->
              <intent-filter>
                     <action android:name="com.android.settings.action.IA_SETTINGS" />
              </intent-filter>
             <!-- Tell Settings app which category it belongs to -->
              <meta-data android:name="com.android.settings.category"
                     android:value="com.android.settings.category.ia.homepage" />
             <!-- Add a summary text when the setting is displayed -->
              <meta-data android:name="com.android.settings.summary"
                     android:resource="@string/display_dashboard_summary"/>
             </activity>

בזמן העיבוד, הפריט יבקש רשימה של העדפות מ-XML סטטי ומתוך הגדרות דינמיות שמוגדרות ב-AndroidManifest. לא משנה אם PreferenceController מוגדרים בקוד Java או ב-XML,‏ DashboardFragment מנהל את לוגיקת הטיפול בכל הגדרה באמצעות PreferenceController (כפי שמוסבר בהמשך). לאחר מכן הם מוצגים בממשק המשתמש כרשימה מעורבת.

PreferenceController

יש הבדלים בין ההטמעה של PreferenceController ב-Android 9 לבין ההטמעה ב-Android 8.x, כפי שמתואר בקטע הזה.

‫PreferenceController בגרסה 9 של Android

PreferenceController מכיל את כל הלוגיקה שנדרשת לאינטראקציה עם ההעדפה, כולל הצגה, עדכון, יצירת אינדקס לחיפוש וכו'.

הממשק של PreferenceController מוגדר כ-BasePreferenceController. לדוגמה, אפשר לראות קוד ב-packages/apps/Settings/src/com/android/settings/core/ BasePreferenceController.java

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

ל-BasePreferenceController יש ממשקי API כמו getAvailabilityStatus(), ‏ displayPreference(),‏ handlePreferenceTreeClicked(), וכו'. תיעוד מפורט לכל API נמצא במחלקת הממשק.

מגבלה על הטמעה של BasePreferenceController (ומחלקות המשנה שלו, כמו TogglePreferenceController) היא שחתימת הבנאי חייבת להיות תואמת לאחת מהאפשרויות הבאות:

  • public MyController(Context context, String key) {}
  • public MyController(Context context) {}

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

DashboardFragment שומר רשימה של PreferenceController במסך. ב-onCreate() של הפרגמנט, כל הבקרים מופעלים עבור השיטה getAvailabilityStatus(), ואם היא מחזירה true, מופעלת השיטה displayPreference() כדי לעבד את לוגיקת התצוגה. getAvailabilityStatus() חשוב גם כדי להגדיר את פריטי המסגרת של ההגדרות שזמינים במהלך החיפוש.

‫PreferenceController בגרסאות Android 8.x

PreferenceController מכיל את כל הלוגיקה לאינטראקציה עם ההעדפה, כולל הצגה, עדכון, יצירת אינדקס לחיפוש וכו'.

בהתאם לאינטראקציות עם ההעדפות, לממשק PreferenceController יש ממשקי API‏ isAvailable(), ‏ displayPreference(), ‏ handlePreferenceTreeClicked() וכו'. תיעוד מפורט על כל API זמין במחלקת הממשק.

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

DashboardFragment שומר רשימה של PreferenceControllers במסך. ב-onCreate() של הפרגמנט, כל בקרים מופעלים עבור השיטה isAvailable(), ואם היא מחזירה true, מופעלת השיטה displayPreference() כדי לעבד את לוגיקת התצוגה.

שימוש ב-DashboardFragment

העברת העדפה מדף א' לדף ב'

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

העברה סטטית ב-Android 9

  1. מאתרים את קובצי ה-XML של ההעדפות לדף המקורי ולדף היעד. אפשר למצוא את המידע הזה בשיטה getPreferenceScreenResId() של הדף.
  2. מסירים את ההעדפה מקובץ ה-XML של הדף המקורי.
  3. מוסיפים את ההעדפה ל-XML של דף היעד.
  4. מסירים את PreferenceController להעדפה הזו מהטמעת Java של הדף המקורי. בדרך כלל זה הנתיב createPreferenceControllers(). יכול להיות שהבקר יוכרז ישירות ב-XML.

    הערה: יכול להיות שההעדפה לא תכלול את PreferenceController.

  5. מציבים את PreferenceController ב-createPreferenceControllers() של דף היעד. אם התג PreferenceController מוגדר ב-XML בדף הישן, צריך להגדיר אותו ב-XML גם בדף החדש.

העברה דינמית ב-Android מגרסה 9

  1. בודקים באיזו קטגוריה נמצאים הדף המקורי ודף היעד. אפשר למצוא את המידע הזה בDashboardFragmentRegistry.
  2. פותחים את קובץ AndroidManifest.xml שמכיל את ההגדרה שרוצים להעביר ומחפשים את רשומת הפעילות שמייצגת את ההגדרה הזו.
  3. מגדירים את ערך המטא-נתונים של הפעילות com.android.settings.category למפתח הקטגוריה של הדף החדש.

העברה סטטית בגרסאות Android 8.x

  1. מחפשים את קובצי ה-XML של ההעדפות לדף המקורי ולדף היעד.
  2. אפשר למצוא את המידע הזה בשיטה getPreferenceScreenResId() של הדף.
  3. מסירים את ההעדפה מקובץ ה-XML של הדף המקורי.
  4. מוסיפים את ההעדפה ל-XML של דף היעד.
  5. מסירים את PreferenceController מההטמעה של Java בדף המקורי. בדרך כלל זה בנתיב getPreferenceControllers().
  6. הערה: יכול להיות שההעדפה לא כוללת PreferenceController.

  7. מציבים את PreferenceController ב-getPreferenceControllers() של דף היעד.

העברה דינמית בגרסאות Android 8.x

  1. בודקים באיזו קטגוריה נמצאים הדף המקורי ודף היעד. המידע הזה מופיע בכתובת DashboardFragmentRegistry.
  2. פותחים את קובץ AndroidManifest.xml שמכיל את ההגדרה שרוצים להעביר ומחפשים את רשומת הפעילות שמייצגת את ההגדרה הזו.
  3. משנים את ערך המטא-נתונים של הפעילות com.android.settings.category, מגדירים את נקודת הערך למפתח הקטגוריה של הדף החדש.

יצירת העדפה חדשה בדף

אם ההעדפה מופיעה באופן סטטי בקובץ ה-XML של ההעדפות בדף המקורי, פועלים לפי ההוראות לשינוי סטטי שבהמשך. אם לא, פועלים בהתאם לתהליך הדינמי.

יצירת העדפה סטטית

  1. מאתרים את קובצי ה-XML של ההעדפות של הדף. אפשר למצוא את המידע הזה בשיטה getPreferenceScreenResId() של הדף.
  2. מוסיפים פריט Preference חדש ב-XML. צריך לוודא שיש לו android:key ייחודי.
  3. מגדירים PreferenceController להעדפה הזו בשיטת getPreferenceControllers() של הדף.
    • ב-Android 8.x ובאופן אופציונלי ב-Android 9, יוצרים מופע של PreferenceController להעדפה הזו ב-method‏ createPreferenceControllers() של הדף.

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

    • החל מ-Android 9, אפשר להצהיר על PreferenceController ב-XML לצד ההעדפה. לדוגמה:
      <Preference
              android:key="reset_dashboard"
              android:title="@string/reset_dashboard_title"
              settings:controller="com.android.settings.system.ResetPreferenceController"/>

יצירת העדפה דינמית

  1. בודקים באיזו קטגוריה נמצאים הדף המקורי ודף היעד. המידע הזה מופיע בכתובת DashboardFragmentRegistry.
  2. יצירת פעילות חדשה ב-AndroidManifest
  3. מוסיפים את המטא-נתונים הדרושים לפעילות החדשה כדי להגדיר את ההגדרה. מגדירים את ערך המטא-נתונים של com.android.settings.category לאותו ערך שהוגדר בשלב 1.

דף חדש

  1. יוצרים פרגמנט חדש, עם ירושה מ-DashboardFragment.
  2. מגדירים את הקטגוריה שלו ב-DashboardFragmentRegistry.

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

  3. פועלים לפי השלבים להוספת ההגדרות שנדרשות לדף הזה. מידע נוסף זמין בקטע הטמעה.

אימות

  • מריצים את בדיקות robolectric בהגדרות. כל הבדיקות הקיימות והחדשות צריכות לעבור.
  • מבצעים Build ומתקינים את ההגדרות, ואז פותחים באופן ידני את הדף שרוצים לשנות. הדף אמור להתעדכן באופן מיידי.