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

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

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

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

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

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

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

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

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

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

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

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

יצירת המשבצת

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

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

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

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

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

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

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

יוצרים שירות לרכיב שמרחיב את המחלקה 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. יכול להיות שיהיה אפשר להפעיל את השיטות האלה מחוץ ל-onCreate() ול-onDestroy(), כי השיטות של מחזור החיים של Service והשיטות של מחזור החיים של TileService מופעלות בשני שרשורים אסינכרוניים נפרדים.

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

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

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

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

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

האפליקציה 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_INACTIVE ו-STATE_UNAVAILABLE הם בהירים יותר.STATE_ACTIVE הגוון המדויק תלוי ביצרן ובגרסה.

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

עדכון האריח

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

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

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

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

  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 שמשמש לאחזור השירות הזה – הוא חייב להיות זהה למשתמש הנוכחי.