برای برنامه‌تان کاشی‌های «تنظیمات فوری» سفارشی بسازید

«تنظیمات فوری» کاشی‌هایی هستند که در پانل تنظیمات فوری نمایش داده می‌شوند، و کنش‌هایی را نشان می‌دهند که کاربران می‌توانند با تک‌ضرب زدن روی آن‌ها، کارهای تکراری را به‌سرعت تکمیل کنند. برنامه شما می‌تواند ازطریق کلاس TileService کاشی سفارشی به کاربران ارائه دهد و از شیء Tile برای ردیابی وضعیت کاشی استفاده کند. برای مثال، می‌توانید کاشی‌ای ایجاد کنید که به کاربران اجازه دهد وی‌پی‌ان ارائه‌شده توسط برنامه‌تان را روشن یا خاموش کنند.

پانل «تنظیمات فوری» با کاشی وی‌پی‌ان روشن
  و خاموش
شکل ۱. پانل «تنظیمات فوری» با کاشی VPN روشن و خاموش می‌شود.

تصمیم بگیرید چه زمانی کاشی ایجاد شود

توصیه می‌کنیم برای عملکردهای خاصی که انتظار دارید کاربران اغلب به آن‌ها دسترسی داشته باشند یا به دسترسی سریع به آن‌ها نیاز داشته باشند (یا هر دو) کاشی ایجاد کنید. مؤثرترین کاشی‌ها آن‌هایی هستند که هر دو این ویژگی‌ها را داشته باشند و دسترسی سریع به کنش‌های پرتکرار را فراهم کنند.

برای مثال، می‌توانید برای برنامه تناسب اندام کاشی‌ای ایجاد کنید که به کاربران اجازه دهد جلسه تمرین را به‌سرعت شروع کنند. اما توصیه نمی‌کنیم برای همان برنامه کاشی‌ای ایجاد کنید که به کاربران اجازه دهد کل سابقه تمرینشان را مرور کنند.

موارد استفاده کاشی برنامه تناسب اندام
شکل ۲. نمونه‌هایی از کاشی‌های توصیه‌شده درمقابل کاشی‌های توصیه‌نشده برای برنامه تناسب اندام.

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

  • از کاشی‌ها برای راه‌اندازی برنامه استفاده نکنید. درعوض، از میان‌بر برنامه یا راه‌انداز استاندارد استفاده کنید.

  • از کاشی‌ها برای کنش‌های یک‌باره کاربر استفاده نکنید. درعوض از میان‌بر برنامه یا اعلان استفاده کنید.

  • از ایجاد کاشی‌های خیلی زیاد خودداری کنید. توصیه می‌کنیم حداکثر دو ویجت برای هر برنامه داشته باشید. به‌جای آن از میان‌بر برنامه استفاده کنید.

  • از کاشی‌هایی که اطلاعات را نمایش می‌دهند اما برای کاربران تعاملی نیستند استفاده نکنید. به‌جای آن از اعلان یا ابزاره استفاده کنید.

ایجاد کاشی

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

نمونه «تنظیمات فوری» مثالی از نحوه ایجاد و مدیریت کاشی ارائه می‌دهد.

ایجاد کردن نماد سفارشی

باید نماد سفارشی ارائه کنید که در کاشی در پانل «تنظیمات فوری» نمایش داده می‌شود. (این نماد را هنگام اعلام TileService اضافه خواهید کرد، که در بخش بعدی شرح داده شده است.) نماد باید سفید یک‌دست با پس‌زمینه شفاف باشد، اندازه آن ۲۴ در ۲۴ پیکسل مستقل از تراکم باشد، و به‌شکل VectorDrawable باشد.

نمونه‌ای از ترسیمی بُرداری
شکل ۳.‏ نمونه‌ای از ترسیمی بُرداری.

نمادی ایجاد کنید که هدف کاشی را به‌صورت دیداری نشان دهد. این کار به کاربران کمک می‌کند تشخیص دهند کاشی شما برای نیازهایشان مناسب است یا نه. برای مثال، می‌توانید نماد کرونومتر را برای کاشی برنامه تناسب اندام ایجاد کنید تا کاربران بتوانند جلسه تمرین را شروع کنند.

ایجاد و اعلام TileService

سرویسی برای کاشی‌تان ایجاد کنید که کلاس TileService را گسترش دهد.

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

TileService را در فایل مانیفست برنامه‌تان اعلام کنید. نام و برچسب TileService خود (حداکثر ۱۸ نویسه برای android:label)، نماد سفارشی که در بخش قبلی ایجاد کردید، و اجازه مناسب را اضافه کنید.

 <!-- 18-character limit for android:label. -->
 <service
     android:name=".MyQSTileService"
     android:exported="true"
     android:label="@string/my_default_tile_label"
     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

علاوه‌بر فراخوانی‌های برگشتی که چرخه حیات خدمات محدودکننده را کنترل می‌کنند، باید روش‌های دیگری را که مختص چرخه حیات TileService است پیاده‌سازی کنید. این روش‌ها ممکن است خارج از onCreate() و onDestroy() فراخوانی شوند زیرا روش‌های چرخه حیات Service و روش‌های چرخه حیات TileService در دو رشته ناهمگام جداگانه فراخوانی می‌شوند.

چرخه حیات TileService شامل روش‌های زیر است که هربار TileService شما وارد فاز جدیدی از چرخه حیات می‌شود، توسط سیستم فراخوانی می‌شوند:

  • onTileAdded(): این روش فقط زمانی فراخوانی می‌شود که کاربر برای اولین‌بار کاشی شما را اضافه کند، و اگر کاربر کاشی شما را بردارد و دوباره اضافه کند. این بهترین زمان برای انجام هرگونه مقداردهی اولیه یک‌باره است. بااین‌حال، ممکن است این کار همه راه‌اندازی‌های لازم را برآورده نکند.

  • onStartListening() و onStopListening(): این روش‌ها هرگاه برنامه‌تان کاشی را به‌روز کند فراخوانده می‌شوند و اغلب فراخوانده می‌شوند. ‫TileService بین onStartListening() و onStopListening() محدود می‌ماند و به برنامه شما اجازه می‌دهد کاشی را تغییر دهد و به‌روزرسانی‌ها را ارسال کند.

  • onTileRemoved(): این روش فقط زمانی فراخوانی می‌شود که کاربر کاشی شما را بردارد.

انتخاب کردن حالت شنیداری

TileService شما در حالت فعال یا غیرفعال گوش می‌دهد. توصیه می‌کنیم از حالت فعال استفاده کنید که باید آن را در مانیفست برنامه اعلام کنید. درغیراین‌صورت، TileService حالت استاندارد است و نیازی به اعلام آن نیست.

فرض نکنید که TileService شما خارج از جفت روش‌های onStartListening() و onStopListening() وجود خواهد داشت.

از حالت فعال برای TileService استفاده کنید که در فرایند خودش گوش می‌دهد و وضعیتش را پایش می‌کند. TileService در حالت فعال برای onTileAdded()، onTileRemoved()، رویدادهای ضربه، و زمانی که فرایند برنامه درخواست می‌کند، محدود می‌شود.

اگر TileService شما وقتی وضعیت کاشی باید توسط فرایند خودش به‌روز شود مطلع می‌شود، حالت فعال را توصیه می‌کنیم. کاشی‌های فعال فشار روی سیستم را محدود می‌کنند زیرا لازم نیست هربار که پانل «تنظیمات فوری» برای کاربر نمایان می‌شود، محدود شوند.

روش ایستا 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_ACTIVE تیره‌ترین هستند، و STATE_INACTIVE و STATE_UNAVAILABLE به‌ترتیب روشن‌تر هستند. رنگ دقیق به سازنده و نسخه بستگی دارد.

کاشی VPN برای نشان دادن وضعیت شیء رنگی شده است
شکل ۴. نمونه‌هایی از کاشی رنگی که وضعیت کاشی را نشان می‌دهد (به‌ترتیب وضعیت‌های فعال، غیرفعال، و غیرقابل‌دسترس).

به‌روزرسانی کاشی

وقتی تماس برگشتی به onStartListening() دریافت کردید، می‌توانید کاشی‌تان را به‌روز کنید. بسته به حالت کاشی، کاشی شما می‌تواند حداقل یک‌بار تا زمان دریافت فراخوانی برگشتی به onStopListening() به‌روز شود.

در حالت فعال، می‌توانید کاشی‌تان را دقیقاً یک‌بار قبل‌از دریافت فراخوانی برگشتی به onStopListening() به‌روز کنید. در حالت غیرفعال، می‌توانید کاشی‌تان را هر چند بار که می‌خواهید بین onStartListening() و onStopListening() به‌روز کنید.

می‌توانید شیء Tile را با فراخوانی getQsTile() بازیابی کنید. برای به‌روزرسانی فیلدهای خاصی از شیء Tile، روش‌های زیر را فراخوانی کنید:

وقتی تنظیم فیلدهای شیء Tile روی مقادیر صحیح تمام شد، باید updateTile() را فراخوانی کنید تا کاشی‌تان به‌روز شود. این کار باعث می‌شود سیستم داده‌های کاشی به‌روزشده را تجزیه کند و واسط کاربر را به‌روز کند.

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 = state.label
    qsTile.state = if (state.enabled) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
    qsTile.icon = state.icon
    qsTile.updateTile()
}

مدیریت ضربه‌ها

اگر کاشی شما در STATE_ACTIVE یا STATE_INACTIVE باشد، کاربران می‌توانند روی آن تک‌ضرب بزنند تا کنشی را راه‌اندازی کنند. سپس سیستم فراخوانی برگشتی onClick() برنامه شما را فراخوانی می‌کند.

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

var counter = 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()
}

راه‌اندازی کادر گفتگو

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 شما باید رفتارش را براساس آن تغییر دهد.

اگر انجام کنش کاشی درحالت قفل ایمن است، از 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
شکل ۵. پیام‌واره Quick Settings Placement API.
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

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

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

اگر کاربر قبلاً به‌اندازه کافی درخواست‌های مربوط به ComponentName را رد کرده باشد، سیستم می‌تواند پردازش درخواست‌ها را متوقف کند. کاربر از Context استفاده‌شده برای بازیابی این سرویس تعیین می‌شود: باید با کاربر فعلی مطابقت داشته باشد.