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

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

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

مفاهیم کلیدی

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

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

سیستم عامل، انتقال بین این حالت‌ها را کنترل می‌کند.

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

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

انتقال سیستم و رفتار پیش‌فرض

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

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

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

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

سفارشی‌سازی رفتار برای حالت Ambient

صرف نظر از رفتار پیش‌فرض سیستم، در تمام نسخه‌های Wear OS می‌توانید ظاهر یا رفتار برنامه خود را در حالت Ambient با استفاده از AmbientLifecycleObserver برای گوش دادن به فراخوانی‌های برگشتی در انتقال حالت‌ها، سفارشی کنید. این حالت با گره "Ambiactive Mode" در فلوچارت زیر نشان داده شده است.

استفاده از 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 ایجاد کنید و آن را در چرخه حیات activity یا composable خود ثبت کنید.

    private val ambientObserver = AmbientLifecycleObserver(activity, ambientCallback)
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        lifecycle.addObserver(ambientObserver)
    
        // ...
    }

  3. برای حذف ناظر در onDestroy() تابع removeObserver() فراخوانی کنید.

    override fun onDestroy() {
        super.onDestroy()
        lifecycle.removeObserver(ambientObserver)
    
        // ...
    }

برای توسعه‌دهندگانی که از Jetpack Compose استفاده می‌کنند، کتابخانه Horologist یک ابزار مفید به نام AmbientAware composable ارائه می‌دهد که پیاده‌سازی این الگو را ساده می‌کند.

متن زمان آگاه از محیط

به عنوان یک استثنا که نیازی به یک ناظر سفارشی ندارد، در Wear OS 6 ویجت TimeText از محیط آگاه است. این ویجت وقتی دستگاه در حالت Ambient قرار دارد، بدون هیچ کد اضافی، به طور خودکار هر دقیقه یک بار به‌روزرسانی می‌شود.

فلوچارت رفتار محیطی

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

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

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

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

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

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

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

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

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()

روشن نگه داشتن صفحه نمایش و جلوگیری از فعال شدن حالت محیطی (Ambient)

در موارد نادر، ممکن است لازم باشد که به طور کامل از ورود دستگاه به حالت Ambient جلوگیری کنید. یعنی برای جلوگیری از Timeout #1. برای انجام این کار، می‌توانید از پرچم پنجره FLAG_KEEP_SCREEN_ON استفاده کنید. این به عنوان قفل بیدارباش عمل می‌کند و دستگاه را در حالت Interactive نگه می‌دارد. از این با احتیاط شدید استفاده کنید زیرا به شدت بر عمر باتری تأثیر می‌گذارد.

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

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

  • کاهش شلوغی بصری و مصرف انرژی نمایشگر. یک رابط کاربری ساده و مینیمالیستی به کاربر نشان می‌دهد که برنامه در حالت کم‌مصرف است و با محدود کردن پیکسل‌های روشن، باتری قابل توجهی را ذخیره می‌کند.
    • حداقل ۸۵٪ صفحه نمایش را سیاه نگه دارید.
    • فقط مهم‌ترین اطلاعات را نمایش دهید و جزئیات ثانویه را به صفحه نمایش تعاملی منتقل کنید.
    • برای آیکون‌ها یا دکمه‌های بزرگ، به جای پر کردن‌های توپر، از خطوط بیرونی استفاده کنید.
    • از بلوک‌های بزرگ با رنگ‌های ثابت و نام‌های تجاری یا تصاویر پس‌زمینه غیرکاربردی خودداری کنید.
  • مدیریت داده‌های پویای قدیمی
    • تابع فراخوانی onUpdateAmbient() فقط به صورت دوره‌ای -- معمولاً یک بار در دقیقه -- فراخوانی می‌شود تا در مصرف انرژی صرفه‌جویی شود. به دلیل این محدودیت، هر داده‌ای که مرتباً تغییر می‌کند -- مانند کرونومتر، ضربان قلب یا مسافت تمرین -- بین به‌روزرسانی‌ها بی‌استفاده می‌شود. برای جلوگیری از نمایش اطلاعات گمراه‌کننده و نادرست، به تابع فراخوانی onEnterAmbient گوش دهید و این مقادیر زنده را با محتوای ثابت جایگزین کنید، مانند -- .
  • طرح‌بندی منسجمی را حفظ کنید
    • عناصر را در حالت‌های تعاملی و محیطی در موقعیت یکسانی نگه دارید تا یک انتقال روان ایجاد شود.
    • همیشه زمان را نشان دهید.
  • از زمینه آگاه باشید
    • اگر کاربر هنگام ورود دستگاه به حالت محیطی در صفحه تنظیمات یا پیکربندی بوده است، به جای نمای تنظیمات، صفحه مرتبط‌تری از برنامه خود را نمایش دهید.
  • رسیدگی به الزامات خاص دستگاه
    • در شیء 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

مثال: اپلیکیشن تمرین ورزشی

یک اپلیکیشن ورزشی را در نظر بگیرید که باید در تمام مدت زمان جلسه تمرینی، معیارهایی را به کاربر نمایش دهد. این اپلیکیشن باید در طول تغییر وضعیت Ambient قابل مشاهده باشد و با صفحه ساعت جایگزین نشود.

برای رسیدن به این هدف، توسعه‌دهنده باید موارد زیر را انجام دهد:

  1. یک AmbientLifecycleObserver پیاده‌سازی کنید تا تغییرات رابط کاربری بین حالت‌های Interactive و Ambient ، مانند کم کردن نور صفحه نمایش و حذف داده‌های غیرضروری را مدیریت کند.
  2. یک طرح‌بندی کم‌مصرف جدید برای حالت Ambient ایجاد کنید که از بهترین شیوه‌ها پیروی کند.
  3. برای جلوگیری از بازگشت سیستم به صفحه ساعت، در طول مدت تمرین از API فعالیت مداوم استفاده کنید.

برای پیاده‌سازی کامل، به نمونه تمرین مبتنی بر compose در GitHub مراجعه کنید. این نمونه همچنین استفاده از composable AmbientAware از کتابخانه Horologist را برای ساده‌سازی مدیریت حالت محیطی در Compose نشان می‌دهد.