برنامه‌های همیشه روشن و حالت محیطی سیستم

این راهنما توضیح می‌دهد چگونه برنامه‌تان را همیشه روشن نگه دارید، چگونه به تغییرات وضعیت انرژی واکنش نشان دهید، و چگونه رفتار برنامه را مدیریت کنید تا ضمن صرفه‌جویی در مصرف باتری، تجربه کاربری خوبی ارائه دهید.

نمایان کردن دائمی برنامه تأثیر قابل‌توجهی بر عمر باتری دارد، بنابراین هنگام افزودن این ویژگی، تأثیر آن بر مصرف انرژی را درنظر بگیرید.

مفاهیم کلیدی

وقتی برنامه Wear OS در حالت تمام‌صفحه نمایش داده می‌شود، در یکی از دو حالت توان قرار دارد:

  • تعاملی: حالت پرقدرتی که در آن صفحه‌نمایش در حداکثر روشنایی قرار دارد و امکان تعامل کامل کاربر را فراهم می‌کند.
  • محیطی: حالتی کم‌مصرف که در آن نمایشگر برای صرفه‌جویی در مصرف انرژی کم‌نور می‌شود. در این حالت، میانای کاربری برنامه شما همچنان تمام صفحه را اشغال می‌کند، اما سیستم ممکن است ظاهر آن را با محو کردن یا نمایش محتوای رونهاد مانند زمان تغییر دهد. این ویژگی حالت محیطی نیز نامیده می‌شود.

سیستم‌عامل گذار بین این وضعیت‌ها را کنترل می‌کند.

برنامه همیشه روشن برنامه‌ای است که محتوا را در هر دو حالت تعاملی و محیطی نمایش می‌دهد.

وقتی برنامه همیشه روشن به نمایش واسط کاربر خود درحالی‌که دستگاه در حالت کم‌مصرف محیطی است ادامه می‌دهد، گفته می‌شود که در حالت محیطی فعال است.

گذار سیستم و رفتار پیش‌فرض

وقتی برنامه‌ای در پیش‌زمینه است، سیستم انتقال وضعیت انرژی را براساس دو زمان‌بندی که با غیرفعال بودن کاربر راه‌اندازی می‌شوند مدیریت می‌کند.

  • مهلت #۱: حالت «تعاملی» به «محیطی»: پس‌از مدتی عدم فعالیت کاربر، دستگاه وارد حالت محیطی می‌شود.
  • مهلت #۲: برگشتن به صفحه ساعت: پس‌از دوره دیگری از عدم فعالیت، سیستم ممکن است برنامه فعلی را پنهان کند و صفحه ساعت را نمایش دهد.

بلافاصله پس‌از اینکه سیستم از اولین گذار به حالت محیطی عبور کرد، رفتار پیش‌فرض به نسخه Wear OS و پیکربندی برنامه شما بستگی دارد:

  • در Wear OS 5 و نسخه‌های پایین‌تر، سیستم نماگرفت محوی از برنامه متوقف‌شده شما را نمایش می‌دهد و زمان را روی آن رونهاد می‌کند. این وضعیت با گره «AOD Lite» در جریان کار زیر نشان داده می‌شود.
  • در Wear OS 6 و نسخه‌های بالاتر، اگر برنامه‌ای SDK 36 یا جدیدتر را هدف‌یابی کند، همیشه روشن درنظر گرفته می‌شود. نمایشگر کم‌نور می‌شود، اما برنامه همچنان اجرا می‌شود و قابل‌مشاهده باقی می‌ماند. (به‌روزرسانی‌ها ممکن است هر دقیقه یک‌بار انجام شود.) این وضعیت با گره «Global AOD» در جریان کار زیر نشان داده می‌شود.

سفارشی‌سازی رفتار برای حالت «محیطی»

صرف‌نظر از رفتار پیش‌فرض سیستم، در همه نسخه‌های Wear OS می‌توانید بااستفاده از LocalAmbientModeManager برای مشاهده گذارهای وضعیت در Jetpack Compose در Wear OS، ظاهر یا رفتار برنامه‌تان را در حالت محیطی سفارشی‌سازی کنید. این وضعیت با گره «حالت فعال محیطی» در جریان کار زیر نشان داده می‌شود.

مشاهده وضعیت محیطی

برای واکنش نشان دادن به رویدادهای حالت محیطی در Jetpack Compose در Wear OS:

  1. از LocalAmbientModeManager برای مشاهده تغییرات وضعیت حالت فراگیر سیستم استفاده کنید و عناصر ترکیبی خود را براساس آن تنظیم کنید. عنصرتان را پیکربندی کنید تا در حالت AmbientMode.Ambient به حالت کم‌مصرف‌تر برود و در حالت AmbientMode.Interactive به نمایشگر تعاملی کامل برگردد.

    // In a production application, the AmbientModeManager should be instantiated and provided at
    // the highest level of the Compose hierarchy (typically in the host Activity's setContent
    // block) using a CompositionLocalProvider. This ensures proper lifecycle management and
    // broad accessibility.
    
    // For this self-contained demo, AmbientModeManager is created and provided locally:
    val activityAmbientModeManager = rememberAmbientModeManager()
    CompositionLocalProvider(LocalAmbientModeManager provides activityAmbientModeManager) {
        val ambientModeManager = LocalAmbientModeManager.current
        val ambientMode = ambientModeManager?.currentAmbientMode
    
        if (ambientModeManager != null) {
            ambientModeManager.AmbientTickEffect {
                // While device is in ambient mode, update properties every minute or so
                // ...
            }
        }
    
        // ...
            val ambientModeName =
                when (ambientMode) {
                    is AmbientMode.Interactive -> "Interactive"
                    is AmbientMode.Ambient -> "Ambient"
                    else -> "Unknown"
                }
    
            Text(text = "$ambientModeName Mode")
            // ...
    }

روندنمای رفتار محیطی

جریان‌نمای زیر نشان می‌دهد که سیستم چگونه رفتار محیطی را براساس نسخه Wear OS دستگاه، targetSdkVersion برنامه شما، و اینکه آیا انتقال‌های حالت محیطی را مشاهده می‌کند (بااستفاده از LocalAmbientModeManager یا AmbientLifecycleCallback) تعیین می‌کند.

روندنمایی که منطق تصمیم‌گیری برای حالت محیطی Wear OS را نشان می‌دهد. این ویدیو نشان می‌دهد که چگونه نسخه سیستم‌عامل دستگاه و پیکربندی برنامه یکی از سه نتیجه را تعیین می‌کند: رونهاد محو، «نمایشگر همیشه روشن جهانی»، یا «حالت فعال محیطی» مدیریت‌شده توسط برنامه.
شکل ۱.: روندنمایی که منطق تصمیم‌گیری برای حالت محیطی Wear OS را نشان می‌دهد.

کنترل مدت روشن بودن صفحه‌نمایش

بخش‌های زیر نحوه مدیریت مدت زمانی را که برنامه در صفحه می‌ماند شرح می‌دهد.

جلوگیری از بازگشت به صفحه ساعت با «فعالیت درحال انجام» یا «به‌روزرسانی زنده»

پس‌از گذشت مدتی در حالت محیطی (مهلت زمانی شماره ۲)، سیستم معمولاً به صفحه ساعت برمی‌گردد. کاربر می‌تواند مدت زمان اتمام مهلت را در تنظیمات سیستم پیکربندی کند. برای برخی موارد استفاده، مثل ردیابی تمرین توسط کاربر، ممکن است لازم باشد برنامه برای مدت طولانی‌تری قابل‌مشاهده بماند.

در Wear OS 5 و نسخه‌های بالاتر، می‌توانید با پیاده‌سازی فعالیت جاری از این کار جلوگیری کنید. اگر برنامه‌تان اطلاعاتی درباره تکلیف کاربر درحال انجامی، مثل جلسه تمرین، نمایش می‌دهد، می‌توانید از میانای برنامه‌سازی کاربردی فعالیت درحال انجام برای نمایان نگه داشتن برنامه‌تان تا پایان تکلیف استفاده کنید. اگر کاربری به‌صورت دستی به صفحه ساعت برگردد، نشانگر فعالیت درحال انجام راهی یک‌ضرب برای بازگشت به برنامه شما دراختیارش قرار می‌دهد.

یا در Wear OS 7 و نسخه‌های بالاتر، می‌توانید به‌جای «فعالیت جاری» از به‌روزرسانی زنده استفاده کنید. برای سازگاری با نسخه‌های قدیمی، همچنان از «فعالیت جاری» در دستگاه‌های دارای Wear OS 6 یا نسخه‌های پایین‌تر پشتیبانی کنید.

برای پیاده‌سازی این مورد، هدف لمس اعلان جاری باید به فعالیت همیشه روشن شما اشاره کند، همان‌طور که در تکه‌کد زیر نشان داده شده است:

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)

val notification = notificationBuilder.build()

صفحه‌نمایش روشن می‌ماند و از وضعیت «محیطی» جلوگیری می‌شود

در موارد نادر، ممکن است لازم باشد به‌طور کامل از ورود دستگاه به حالت گزینشی جلوگیری کنید. یعنی برای جلوگیری از «مهلت زمانی #۱». برای انجام این کار، می‌توانید از keepScreenOn اصلاح‌گر استفاده کنید. این عملکرد به‌عنوان قفل بیداری عمل می‌کند و دستگاه را در حالت تعاملی نگه می‌دارد. از این ویژگی با احتیاط زیاد استفاده کنید زیرا تأثیر شدیدی بر عمر باتری دارد.

توصیه‌هایی برای «حالت محیطی»

برای ارائه بهترین تجربه کاربری و صرفه‌جویی در مصرف باتری در حالت محیطی، این دستورالعمل‌های طراحی را دنبال کنید. این توصیه‌ها با جلوگیری از اطلاعات گمراه‌کننده و کاهش درهم‌ریختگی بصری، تجربه کاربری واضح را در اولویت قرار می‌دهند و درعین‌حال، توان نمایشگر را بهینه می‌کنند.

  • درهم‌ریختگی دیداری و قدرت نمایش را کاهش دهید. میانای کاربر تمیز و مینیمالیستی به کاربر نشان می‌دهد که برنامه در حالت کم‌مصرف است و با محدود کردن پیکسل‌های روشن، باتری را به‌میزان قابل‌توجهی ذخیره می‌کند.
    • حداقل ۸۵٪ از صفحه‌نمایش را سیاه نگه دارید (نسبت پیکسل روشن ۱۵٪ یا کمتر).
    • فقط مهم‌ترین اطلاعات را نشان دهید و جزئیات ثانویه را به نمایشگر تعاملی منتقل کنید.
    • به‌جای رنگ‌های یکدست، از خطوط محیطی برای نمادها یا دکمه‌های بزرگ استفاده کنید، کنتراست خطوط محیطی را تنظیم کنید تا عناصر بدون خطر پرش صفحه یا سوختگی صفحه خوانا باقی بمانند.
    • از بلوک‌های بزرگ رنگ یکدست و نمانام‌سازی غیرکاربردی یا تصاویر پس‌زمینه اجتناب کنید.
  • مدیریت داده‌های پویا و پویانمایی‌های قدیمی
    • برای صرفه‌جویی در مصرف انرژی، کاربرگشتی AmbientTickEffect فقط به‌صورت دوره‌ای -- معمولاً یک‌بار در دقیقه -- فراخوانده می‌شود. به‌دلیل این محدودیت، هر داده‌ای که به‌طور مکرر تغییر می‌کند -- مانند زمان‌سنج، ضربان قلب، یا مسافت تمرین -- بین به‌روزرسانی‌ها قدیمی می‌شود. برای اجتناب از نمایش اطلاعات گمراه‌کننده و نادرست، این مقادیر زنده را با محتوای جای‌بان ایستا، مثل --، جایگزین کنید.
    • نشانگرهای پیشرفتی را که برای مفید بودن در بافت یا وضعیت فعلی کاربر نیاز به به‌روزرسانی‌های مکرر دارند بردارید، مثل حلقه‌های پیشرفت برای جلسه‌های رسانه‌ای کوتاه. می‌توانید نشانگرهای پیشرفت را در جایی که به‌روزرسانی‌های یک‌بار در دقیقه همچنان ارزش دارند، مانند تایمرهای طولانی، حفظ کنید.
    • همه پویانمایی‌ها را در حالت محیطی، ازجمله نشانگرهای پیشرفت پویانمایی‌شده و نوشتار گردان، موقتاً متوقف یا بردارید.
  • حفظ چیدمان یکنواخت
    • عناصر را در موقعیت یکسانی در حالت‌های تعاملی و محیطی نگه دارید تا انتقال روان ایجاد شود. عناصر تعاملی رابط کاربری مثل دکمه‌ها می‌توانند نمایان بمانند زیرا دستگاه‌های مدرن Wear OS از ورودی لمسی درطول جلسه‌های محیطی پشتیبانی می‌کنند.
    • همیشه زمان فعلی نشان داده شود. در Jetpack Compose برای Wear OS، TimeText (به‌طور پیش‌فرض در ScreenScaffold گنجانده شده است) با محیط اطراف سازگار است و در حالت محیطی، هر دقیقه یک‌بار به‌طور خودکار به‌روزرسانی می‌شود.
  • به بافتار توجه کنید
    • اگر کاربر هنگام ورود دستگاه به حالت محیطی در صفحه تنظیمات یا پیکربندی بود، به‌جای نمای تنظیمات، صفحه مرتبط‌تری از برنامه‌تان را نمایش دهید.
  • رسیدگی به الزامات مختص دستگاه
    • وقتی currentAmbientMode برمی‌گردد AmbientMode.Ambient:
      • اگر isLowBitAmbientSupported true باشد، نمایشگر در حالت محیطی از بیت‌های کمتری برای هر رنگ پشتیبانی می‌کند. «ضد دندانه‌دار کردن» را غیرفعال کنید (برای مثال، در عملیات‌های رسم سفارشی Canvas یا Paint) و درصورت امکان از گرادیان‌های رنگی استفاده نکنید.
      • اگر isBurnInProtectionRequired روی true تنظیم شده باشد، سیستم به‌طور دوره‌ای محتوای نمایشگر را جابه‌جا می‌کند تا از سوختگی پیکسل جلوگیری شود. عناصر میانای کاربر را به‌صورت دستی در برنامه‌تان جابه‌جا نکنید. درعوض، از نواحی سفید یکپارچه اجتناب کنید و عناصر میانای کاربر مهم را حداقل ۱۰ پیکسل دور از لبه صفحه‌نمایش قرار دهید تا وقتی سیستم نمایشگر را جابه‌جا می‌کند، این عناصر بریده نشوند. (چیدمان‌های «نوشتن استاندارد Wear» مثل ScreenScaffold ازقبل حاشیه کافی در لبه‌ها ارائه می‌دهند.)

عیب‌یابی و آزمایش

این فرمان‌های 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. از LocalAmbientModeManager برای مدیریت تغییرات میانای کاربر بین حالت‌های تعاملی و محیطی، مانند کم کردن نور صفحه و برداشتن داده‌های غیرضروری استفاده کنید.
  2. چیدمان کم‌مصرف جدیدی برای حالت محیطی ایجاد کنید که از روال‌های مطلوب پیروی کند.
  3. از میانای برنامه‌سازی کاربردی فعالیت جاری (یا به‌روزرسانی‌های زنده در Wear OS 7 و نسخه‌های بالاتر) درطول تمرین استفاده کنید تا سیستم به صفحه ساعت برنگردد.

برای اجرای کامل، نمونه تمرین مبتنی بر نوشتن را در GitHub ببینید. این نمونه همچنین استفاده از عنصر ترکیبی LocalAmbientModeManager را برای ساده کردن مدیریت حالت محیطی در Compose نشان می‌دهد.