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

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