אפליקציות שפועלות כל הזמן ומצב רגישות של המערכת

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

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

מושגים מרכזיים

כשאפליקציה של Wear OS מוצגת במסך מלא, היא נמצאת באחד משני מצבי צריכת אנרגיה:

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

מערכת ההפעלה קובעת את המעבר בין המצבים האלה.

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

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

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

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

  • זמן קצוב לתפוגה מס' 1: מצב אינטראקטיבי למצב אווירה: אחרי פרק זמן של חוסר פעילות של המשתמש, המכשיר עובר למצב אווירה.
  • זמן קצוב מס' 2: חזרה לתצוגת השעון: אחרי פרק זמן נוסף של חוסר פעילות, המערכת עשויה להסתיר את האפליקציה הנוכחית ולהציג את תצוגת השעון.

מיד אחרי שהמערכת עוברת את המעבר הראשון למצב Ambient, התנהגות ברירת המחדל תלויה בגרסה של Wear OS ובהגדרות של האפליקציה:

  • ב-Wear OS 5 וגרסאות ישנות יותר, המערכת מציגה צילום מסך מטושטש של האפליקציה המושהית, עם השעה מעליהם.
  • ב-Wear OS 6 ואילך, אם אפליקציה מטרגטת ל-SDK 36 ואילך, היא נחשבת לאפליקציה שפועלת תמיד. המסך יעומעם, אבל האפליקציה תמשיך לפעול ותישאר גלויה. (העדכונים עשויים להתבצע בתדירות של פעם בדקה).

התאמה אישית של ההתנהגות במצב אווירה

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

שימוש ב-AmbientLifecycleObserver

כדי להגיב לאירועים בתאורת האווירה, משתמשים במחלקה AmbientLifecycleObserver:

  1. מטמיעים את הממשק AmbientLifecycleObserver.AmbientLifecycleCallback. משתמשים בשיטה onEnterAmbient() כדי להתאים את ממשק המשתמש למצב של צריכת אנרגיה נמוכה, ובשיטה onExitAmbient() כדי לשחזר אותו לתצוגה האינטראקטיבית המלאה.

    val ambientCallback = object : AmbientLifecycleObserver.AmbientLifecycleCallback {
        override fun onEnterAmbient(ambientDetails: AmbientLifecycleObserver.AmbientDetails) {
            // ... Called when moving from interactive mode into ambient mode.
            // Adjust UI for low-power state: dim colors, hide non-essential elements.
        }
    
        override fun onExitAmbient() {
            // ... Called when leaving ambient mode, back into interactive mode.
            // Restore full UI.
        }
    
        override fun onUpdateAmbient() {
            // ... Called by the system periodically (typically once per minute)
            // to allow the app to update its display while in ambient mode.
        }
    }
    
  2. יוצרים AmbientLifecycleObserver ומירשם אותו במחזור החיים של הפעילות או הרכיב הניתן לקיבוץ.

    private val ambientObserver = AmbientLifecycleObserver(activity, ambientCallback)
    
    override fun onCreate(savedInstanceState: Bundle) {
        super.onCreate(savedInstanceState)
        lifecycle.addObserver(ambientObserver)
    
        // ...
    }
    
  3. קוראים לפונקציה removeObserver() כדי להסיר את הצופה ב-onDestroy().

למפתחים שמשתמשים ב-Jetpack Compose, ספריית Horologist מספקת כלי שימושי, ה-composable‏ AmbientAware, שמפשט את ההטמעה של התבנית הזו.

TimeText עם תמיכה בסביבה

בניגוד לדרישות לגבי משקיף בהתאמה אישית, ב-Wear OS 6 הווידג'ט TimeText מתאים לסביבה. הוא מתעדכן באופן אוטומטי פעם בדקה כשהמכשיר נמצא במצב Ambient, בלי קוד נוסף.

שליטה במשך הזמן שבו המסך מופעל

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

איך למנוע חזרה לתצוגת השעון כשיש פעילות מתמשכת

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

בגרסה 5 ואילך של Wear OS, אפשר למנוע זאת על ידי הטמעת פעילות מתמשכת. אם האפליקציה שלכם מציגה מידע על משימה מתמשכת של המשתמש, כמו סשן אימון, תוכלו להשתמש ב-Ongoing Activity API כדי שהאפליקציה תישאר גלויה עד שהמשימה תסתיים. אם משתמש חוזר לתצוגת השעון באופן ידני, האינדיקטור של הפעילות המתמשכת מאפשר לו לחזור לאפליקציה בלחיצה אחת.

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

private fun createNotification(): Notification {
    val activityIntent =
        Intent(this, AlwaysOnActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
        }

    val pendingIntent =
        PendingIntent.getActivity(
            this,
            0,
            activityIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
        )

    val notificationBuilder =
        NotificationCompat.Builder(this, CHANNEL_ID)
            // ...
            // ...
            .setOngoing(true)

    // ...

    val ongoingActivity =
        OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
            // ...
            // ...
            .setTouchIntent(pendingIntent)
            .build()

    ongoingActivity.apply(applicationContext)

    return notificationBuilder.build()
}

שמירת המסך במצב פעולה ומניעת מצב אווירה

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

המלצות למצב אווירה

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

  • שימוש במסך מינימליסטי עם צריכת אנרגיה נמוכה
    • לפחות 85% מהמסך צריכים להיות שחורים.
    • כדאי להשתמש בקווי מתאר לסמלים או ללחצנים גדולים במקום במילוי אחיד.
    • כדאי להציג רק את המידע הכי קריטי ולהעביר את הפרטים המשניים למסך האינטראקטיבי.
    • כדאי להימנע מבלוק גדול של צבע אחיד וממיתוג או תמונות רקע לא פונקציונליים.
  • מוודאים שהתוכן מתעדכן בצורה מתאימה
    • לגבי נתונים שמשתנים לעיתים קרובות, כמו שעון סטופ, מרחק האימון או הזמן, כדאי להציג תוכן placeholder כמו -- כדי לא ליצור רושם שהתוכן עדכני.
    • הסרת אינדיקטורים להתקדמות שמתעדכנים באופן רציף, כמו צלצולים של ספירה לאחור וסשנים של מדיה.
    • צריך להשתמש בקריאה החוזרת onUpdateAmbient() רק לעדכונים חיוניים, בדרך כלל פעם בדקה.
  • שמירה על פריסה עקבית
    • כדי ליצור מעבר חלק, חשוב שהרכיבים יישארו באותו מיקום במצבים אינטראקטיבי ותאורה רגילה.
    • תמיד להציג את השעה.
  • התמקדות בהקשר
    • אם המשתמש היה במסך הגדרות או תצורה כשהמכשיר עבר למצב אווירה, מומלץ להציג מסך רלוונטי יותר מהאפליקציה במקום תצוגת ההגדרות.
  • טיפול בדרישות ספציפיות למכשיר
    • באובייקט AmbientDetails שמוענק ל-onEnterAmbient():
      • אם הערך של deviceHasLowBitAmbient הוא true, משביתים את החלקת הקצוות (anti-aliasing) במידת האפשר.
      • אם הערך של burnInProtectionRequired הוא true, כדאי להזיז מדי פעם את רכיבי ממשק המשתמש מעט ולהימנע מאזורים לבנים מוצקים כדי למנוע שריפת פיקסלים במסך.

ניפוי באגים ובדיקה

הפקודות הבאות של adb יכולות להיות שימושיות במהלך הפיתוח או הבדיקה של אופן ההתנהגות של האפליקציה כשהמכשיר נמצא במצב אווירה:

# put device in ambient mode if the always on display is enabled in settings
# (and not disabled by other settings, such as theatre mode)
$ adb shell input keyevent KEYCODE_SLEEP

# put device in interactive mode
$ adb shell input keyevent KEYCODE_WAKEUP

דוגמה: אפליקציית אימון

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

כדי לעשות זאת, המפתח צריך לבצע את הפעולות הבאות:

  1. מטמיעים AmbientLifecycleObserver כדי לטפל בשינויים בממשק המשתמש בין המצבים אינטראקטיבי וסביבתי, כמו עמעום המסך והסרה של נתונים לא חיוניים.
  2. יוצרים פריסה חדשה עם צריכת אנרגיה נמוכה למצב Ambient בהתאם לשיטות המומלצות.
  3. משתמשים ב-Ongoing Activity API למשך האימון כדי למנוע מהמערכת לחזור לתצוגת השעון.

להטמעה מלאה, אפשר לעיין בתרגיל לדוגמה שמבוסס על compose ב-GitHub. בדוגמה הזו מוצג גם השימוש ב-composable‏ AmbientAware מספריית Horologist כדי לפשט את הטיפול במצב אווירה ב-Compose.