יצירת כרטיסי מידע מותאמים אישית בהגדרות המהירות לאפליקציה

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

חלונית ההגדרות המהירות עם הכפתור של ה-VPN במצב מופעל ומושבת
איור 1. חלונית ההגדרות המהירות עם הכפתור של ה-VPN במצב מופעל ומושבת.

מתי כדאי ליצור משבצת

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

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

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

כדי לשפר את יכולת הגילוי של המשבצת ואת קלות השימוש בה, מומלץ להימנע משיטות מסוימות:

  • לא מומלץ להשתמש במשבצות כדי להפעיל אפליקציה. במקום זאת, כדאי להשתמש בקיצור דרך לאפליקציה או במפעיל אפליקציות רגיל.

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

  • לא מומלץ ליצור יותר מדי משבצות. מומלץ להשתמש במקסימום שני קיצורי דרך לכל אפליקציה. אפשר להשתמש בקיצור דרך לאפליקציה במקום זאת.

  • אל תשתמשו במשבצות שמציגות מידע אבל לא מאפשרות למשתמשים לבצע פעולות. במקום זאת, אפשר להשתמש בהתראה או בווידג'ט.

יצירת משבצת

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

בדוגמה של ההגדרות המהירות מוסבר איך ליצור ולנהל לחצן.

יצירת סמל בהתאמה אישית

צריך לספק סמל מותאם אישית שיוצג במשבצת בחלונית ההגדרות המהירות. (תוסיפו את הסמל הזה כשמצהירים על TileService, כפי שמתואר בקטע הבא). הסמל צריך להיות לבן מלא עם רקע שקוף, בגודל ‎24 x 24dp ובפורמט VectorDrawable.

דוגמה לפריט גרפי וקטורי שניתן לשרטוט
איור 3. דוגמה לפריט גרפי וקטורי שניתן לשרטוט.

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

יצירה והצהרה של TileService

יוצרים שירות לרכיב ה-Tile שמרחיב את המחלקה TileService.

Kotlin

class MyQSTileService: TileService() {

  // Called when the user adds your tile.
  override fun onTileAdded() {
    super.onTileAdded()
  }
  // Called when your app can update your tile.
  override fun onStartListening() {
    super.onStartListening()
  }

  // Called when your app can no longer update your tile.
  override fun onStopListening() {
    super.onStopListening()
  }

  // Called when the user taps on your tile in an active or inactive state.
  override fun onClick() {
    super.onClick()
  }
  // Called when the user removes your tile.
  override fun onTileRemoved() {
    super.onTileRemoved()
  }
}

Java

public class MyQSTileService extends TileService {

  // Called when the user adds your tile.
  @Override
  public void onTileAdded() {
    super.onTileAdded();
  }

  // Called when your app can update your tile.
  @Override
  public void onStartListening() {
    super.onStartListening();
  }

  // Called when your app can no longer update your tile.
  @Override
  public void onStopListening() {
    super.onStopListening();
  }

  // Called when the user taps on your tile in an active or inactive state.
  @Override
  public void onClick() {
    super.onClick();
  }

  // Called when the user removes your tile.
  @Override
  public void onTileRemoved() {
    super.onTileRemoved();
  }
}

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

 <service
     android:name=".MyQSTileService"
     android:exported="true"
     android:label="@string/my_default_tile_label"  // 18-character limit.
     android:icon="@drawable/my_default_icon_label"
     android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
     <intent-filter>
         <action android:name="android.service.quicksettings.action.QS_TILE" />
     </intent-filter>
 </service>

ניהול TileService

אחרי שיוצרים את TileService ומצהירים עליו בקובץ מניפסט של אפליקציה, צריך לנהל את המצב שלו.

TileService הוא שירות מאוגד. ה-TileService שלכם נקשר כשמתקבלת בקשה מהאפליקציה או אם המערכת צריכה לתקשר איתו. מחזור החיים של שירות מאוגד כולל בדרך כלל את ארבע שיטות הקריאה החוזרת הבאות: onCreate(),‏ onBind(),‏ onUnbind() ו-onDestroy(). המערכת מפעילה את השיטות האלה בכל פעם שהשירות עובר לשלב חדש במחזור החיים.

סקירה כללית על מחזור החיים של TileService

בנוסף לקריאות החוזרות (callbacks) ששולטות במחזור החיים של השירות המקשר, צריך להטמיע שיטות אחרות שספציפיות למחזור החיים של TileService. יכול להיות שה-methods האלה יופעלו מחוץ ל-onCreate() ול-onDestroy(), כי ה-methods של מחזור החיים של Service וה-methods של מחזור החיים של TileService מופעלים בשני שרשורים אסינכרוניים נפרדים.

מחזור החיים TileService מכיל את השיטות הבאות, שהמערכת מפעילה בכל פעם שהרכיב TileService עובר לשלב חדש במחזור החיים:

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

  • onStartListening() ו-onStopListening(): הפונקציות האלה מופעלות בכל פעם שהאפליקציה מעדכנת את האריח, והן מופעלות לעיתים קרובות. האפליקציה TileService נשארת מקושרת בין onStartListening() לבין onStopListening(), ומאפשרת לאפליקציה לשנות את הלחצן ולשלוח עדכונים.

  • onTileRemoved(): השיטה הזו מופעלת רק אם המשתמש מסיר את המשבצת שלכם.

בחירת מצב האזנה

האפליקציה TileService פועלת במצב פעיל או במצב לא פעיל. מומלץ להשתמש במצב פעיל, שצריך להצהיר עליו בקובץ המניפסט של האפליקציה. אחרת, TileService הוא המצב הרגיל ואין צורך להצהיר עליו.

אל תניחו שTileService יתקיים מחוץ לזוג השיטות onStartListening() ו-onStopListening().

משתמשים במצב פעיל עבור TileService שמקשיב למצב שלו ועוקב אחריו בתהליך משלו. TileService במצב פעיל מחויב ב-onTileAdded(), onTileRemoved(), באירועי הקשה ובבקשות של תהליך האפליקציה.

מומלץ להשתמש במצב פעיל אם TileService מקבל הודעה כשהמצב של המשבצת צריך להתעדכן על ידי התהליך שלו. האריחים הפעילים מגבילים את העומס על המערכת כי הם לא צריכים להיות קשורים בכל פעם שהחלונית 'הגדרות מהירות' הופכת גלויה למשתמש.

אפשר להפעיל את ה-method הסטטית TileService.requestListeningState() כדי לבקש להתחיל את מצב ההאזנה ולקבל קריאה חוזרת אל onStartListening().

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

<service ...>
    <meta-data android:name="android.service.quicksettings.ACTIVE_TILE"
         android:value="true" />
    ...
</service>

מצב לא פעיל

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

האפליקציה מקבלת קריאה חוזרת אל onStartListening() אחרי שהמשתמש פותח את חלונית ההגדרות המהירות. אפשר לעדכן את אובייקט Tile כמה פעמים שרוצים בין התאריכים onStartListening() ל-onStopListening().

אין צורך להצהיר על מצב לא פעיל – פשוט לא מוסיפים את התג META_DATA_ACTIVE_TILE לקובץ המניפסט של האפליקציה.

סקירה כללית של מצבי הכרטיסים

אחרי שמשתמש מוסיף את המשבצת שלכם, היא תמיד תהיה באחד מהמצבים הבאים.

  • STATE_ACTIVE: מציין מצב פעיל או מופעל. במצב הזה, המשתמש יכול לקיים אינטראקציה עם המשבצת שלכם.

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

  • STATE_INACTIVE: מציין מצב מושבת או מושהה. במצב הזה, המשתמש יכול לקיים אינטראקציה עם המשבצת שלכם.

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

  • STATE_UNAVAILABLE: מציין מצב של זמינות זמנית. המשתמש לא יכול לבצע פעולות במשבצת שלכם כשהיא במצב הזה.

    לדוגמה, אם מופיעה משבצת עם STATE_UNAVAILABLE, המשמעות היא שהמשתמש לא יכול להשתמש במשבצת הזו כרגע מסיבה כלשהי.

המערכת מגדירה רק את המצב הראשוני של אובייקט Tile. אתם מגדירים את המצב של האובייקט Tile לאורך שאר מחזור החיים שלו.

יכול להיות שהמערכת תצבע את סמל המשבצת ואת הרקע כדי לשקף את הסטטוס של אובייקט Tile. אובייקטים עם ההגדרה Tile הם הכהים ביותר, ואובייקטים עם ההגדרות STATE_ACTIVESTATE_INACTIVE ו-STATE_UNAVAILABLE הם בהירים יותר. הגוון המדויק תלוי ביצרן ובגרסה.

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

עדכון המשבצת

אחרי שתקבלו שיחת טלפון חוזרת למספר onStartListening(), תוכלו לעדכן את המשבצת. בהתאם למצב של ה-tile, הוא יכול להתעדכן לפחות פעם אחת עד לקבלת קריאה חוזרת אל onStopListening().

במצב פעיל, אפשר לעדכן את ה-tile בדיוק פעם אחת לפני שמקבלים קריאה חוזרת אל onStopListening(). במצב לא פעיל, אפשר לעדכן את המשבצת כמה פעמים שרוצים בין השעות onStartListening() ל-onStopListening().

אפשר לאחזר את אובייקט Tile באמצעות קריאה ל-getQsTile(). כדי לעדכן שדות ספציפיים באובייקט Tile, קוראים לשיטות הבאות:

אחרי שמגדירים את השדות של אובייקט Tile לערכים הנכונים, צריך להתקשר אל updateTile() כדי לעדכן את האריח. המערכת תנתח את נתוני האריח המעודכנים ותעדכן את ממשק המשתמש.

Kotlin

data class StateModel(val enabled: Boolean, val label: String, val icon: Icon)

override fun onStartListening() {
  super.onStartListening()
  val state = getStateFromService()
  qsTile.label = state.label
  qsTile.contentDescription = tile.label
  qsTile.state = if (state.enabled) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
  qsTile.icon = state.icon
  qsTile.updateTile()
}

Java

public class StateModel {
  final boolean enabled;
  final String label;
  final Icon icon;

  public StateModel(boolean e, String l, Icon i) {
    enabled = e;
    label = l;
    icon = i;
  }
}

@Override
public void onStartListening() {
  super.onStartListening();
  StateModel state = getStateFromService();
  Tile tile = getQsTile();
  tile.setLabel(state.label);
  tile.setContentDescription(state.label);
  tile.setState(state.enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
  tile.setIcon(state.icon);
  tile.updateTile();
}

טיפול בהקשות

אם הריבוע שלכם נמצא בSTATE_ACTIVE או בSTATE_INACTIVE, המשתמשים יכולים להקיש עליו כדי להפעיל פעולה. לאחר מכן המערכת מפעילה את הקריאה החוזרת (callback) onClick() של האפליקציה.

אחרי שהאפליקציה מקבלת קריאה חוזרת אל onClick(), היא יכולה להפעיל תיבת דו-שיח או פעילות, להפעיל עבודה ברקע או לשנות את המצב של הלחצן.

Kotlin

var clicks = 0
override fun onClick() {
  super.onClick()
  counter++
  qsTile.state = if (counter % 2 == 0) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
  qsTile.label = "Clicked $counter times"
  qsTile.contentDescription = qsTile.label
  qsTile.updateTile()
}

Java

int clicks = 0;

@Override
public void onClick() {
  super.onClick();
  counter++;
  Tile tile = getQsTile();
  tile.setState((counter % 2 == 0) ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
  tile.setLabel("Clicked " + counter + " times");
  tile.setContentDescription(tile.getLabel());
  tile.updateTile();
}

הפעלת תיבת דו-שיח

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

הפעלת פעילות

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

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

הקשה ארוכה על משבצת פותחת את המסך פרטי האפליקציה למשתמש. כדי לשנות את ההתנהגות הזו ולהפעיל פעילות להגדרת העדפות, מוסיפים <intent-filter> לאחת מהפעילויות עם ACTION_QS_TILE_PREFERENCES.

החל מ-Android API 28, ל-PendingIntent חייב להיות Intent.FLAG_ACTIVITY_NEW_TASK:

if (Build.VERSION.SDK_INT >= 28) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}

אפשר גם להוסיף את הדגל AndroidManifest.xml בקטע Activity הספציפי.

סימון המשבצת כניתנת להפעלה ולהשבתה

מומלץ לסמן את המשבצת כניתנת להחלפה אם היא פועלת בעיקר כמתג דו-מצבי (שזה אופן הפעולה הנפוץ ביותר של משבצות). המידע הזה עוזר לספק למערכת ההפעלה מידע על ההתנהגות של האריח ולשפר את הנגישות הכוללת.

מגדירים את המטא-נתונים TOGGLEABLE_TILE לערך true כדי לסמן את המשבצת כניתנת להחלפה.

<service ...>
  <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE"
    android:value="true" />
</service>

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

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

אם הפעולה של הלחצן ב-Quick Settings בטוחה לביצוע כשהמכשיר נעול, אפשר להשתמש ב-startActivity() כדי להפעיל פעילות מעל מסך הנעילה.

אם הפעולה של האריח לא בטוחה, משתמשים ב-unlockAndRun() כדי לבקש מהמשתמש לבטל את הנעילה של המכשיר. אם הפעולה בוצעה ללא שגיאות, המערכת מבצעת את אובייקט Runnable שמועבר לשיטה הזו.

סיווג המשבצת

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

הטמעה

כדי לציין קטגוריה ל-TileService, מוסיפים שדה מטא-נתונים להצהרת השירות בקובץ AndroidManifest.xml:

  • ב-AndroidManifest.xml, בתוך רכיב <service> של TileService, מוסיפים רכיב <meta-data>.
  • android:name: צריך להגדיר את הערך הזה ל-android.service.quicksettings.TILE_CATEGORY.
  • android:value: מקצים אחת מקבועי הקטגוריות שהוגדרו מראש, כמו android.service.quicksettings.CATEGORY_CONNECTIVITY או android.service.quicksettings.CATEGORY_DISPLAY.

כמו בדוגמה הבאה:

<service
    android:name=".MyConnectivityTileService"
    [...]
    >
    <meta-data android:name="android.service.quicksettings.TILE_CATEGORY"
        android:value="android.service.quicksettings.CATEGORY_CONNECTIVITY" />
</service>

ה-API מספק קבוצה של קטגוריות מוגדרות מראש שאפשר לבחור מתוכן. הקטגוריות האלה מוגדרות כקבועי מחרוזת במחלקה TileService.

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

  • מאפליקציות מערכת: לגבי משבצות שהן חלק מאפליקציית מערכת.
  • מאפליקציות שהתקנתם: לריבועים מאפליקציות שהמשתמשים התקינו.

למרות שמכשירי Google Pixel משתמשים בקטגוריות בהגדרות המהירות, יצרני ציוד מקורי יכולים להשתמש במידע הזה או להתעלם ממנו בממשקי המשתמש של המערכת שלהם.

בקשה מהמשתמש להוסיף את המשבצת

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

  1. מחליקים למטה כדי לפתוח את חלונית ההגדרות המהירות.
  2. מקישים על לחצן העריכה.
  3. גוללים בין כל כרטיסי המידע במכשיר עד שמאתרים את כרטיס המידע שלכם.
  4. לוחצים לחיצה ארוכה על הכפתור וגוררים אותו לרשימת הכפתורים הפעילים.

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

החל מ-Android 13, אפשר להשתמש בשיטה requestAddTileService() כדי להקל על המשתמשים להוסיף את הריבוע שלכם למכשיר. בשיטה הזו, המשתמשים מקבלים בקשה להוסיף את הכפתור שלכם ישירות לחלונית ההגדרות המהירות. ההנחיה כוללת את שם האפליקציה, התווית שסופקה והסמל.

הנחיה של Quick Settings Placement API
איור 5. הנחיה של Quick Settings Placement API.
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

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

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

המערכת יכולה להפסיק לעבד בקשות עבור ComponentName מסוים אם המשתמש דחה אותו מספיק פעמים בעבר. המשתמש נקבע לפי Context שמשמש לאחזור השירות הזה – הוא חייב להיות זהה למשתמש הנוכחי.