إنشاء مربّعات مخصّصة للإعدادات السريعة لتطبيقك

"الإعدادات السريعة" هي مربّعات يتم عرضها في لوحة الإعدادات السريعة، ويمثّل كلّ مربّع إجراءً يمكن للمستخدمين النقر عليه لإكمال المهام المتكرّرة بسرعة. يمكن لتطبيقك تقديم مربّع معلومات مخصّص للمستخدمين من خلال فئة TileService ، واستخدام عنصر Tile لتتبُّع حالة مربّع المعلومات. على سبيل المثال، يمكنك إنشاء مربّع يتيح للمستخدمين تفعيل شبكة VPN التي يوفّرها تطبيقك أو إيقافها.

لوحة "الإعدادات السريعة" مع تفعيل مربّع VPN
  وإيقافه
الشكل 1. لوحة "الإعدادات السريعة" مع تفعيل مربّع VPN وإيقافه

تحديد حالات إنشاء مربّع معلومات

ننصحك بإنشاء مربّعات وظائف معيّنة تتوقّع أن يستخدمها المستخدمون بشكل متكرّر أو يحتاجون إلى الوصول إليها بسرعة (أو كليهما). إنّ المربّعات الأكثر فعالية هي تلك التي تتوافق مع كلتا السمتَين، ما يتيح الوصول السريع إلى الإجراءَين المُجرَيين بشكل متكرّر.

على سبيل المثال، يمكنك إنشاء مربّع لتطبيق لياقة بدنية يتيح للمستخدمين بدء جلسة تمرين بسرعة. ومع ذلك، لا ننصح بإنشاء مربّع شاشة للتطبيق نفسه يتيح للمستخدمين مراجعة سجلّ التمارين بالكامل.

حالات استخدام مربّعات تطبيقات اللياقة البدنية
الشكل 2. أمثلة على مربّعات مقترَحة مقابل مربّعات غير مقترَحة لتطبيق لياقة بدنية

للمساعدة في تحسين قابلية اكتشاف مربّع التطبيق وسهولة استخدامه، ننصحك بتجنُّب ممارسات معيّنة:

  • تجنَّب استخدام مربّعات التطبيقات لتشغيل تطبيق. استخدِم اختصار تطبيق أو مشغّل تطبيقات عادي بدلاً من ذلك.

  • تجنَّب استخدام المربّعات لإجراءات المستخدم لمرة واحدة. استخدِم اختصار تطبيق أو إشعارًا بدلاً من ذلك.

  • تجنَّب إنشاء الكثير من المربّعات. ننصح باستخدام اثنين بحد أقصى لكل تطبيق. استخدِم بدلاً من ذلك ملف Shortcut لتطبيق.

  • تجنَّب استخدام مربّعات تعرض معلومات، ولكنها ليست تفاعلية للمستخدمين. استخدِم إشعارًا أو تطبيقًا مصغّرًا بدلاً من ذلك.

إنشاء مربّع معلومات

لإنشاء مربّع معلومات، عليك أولاً إنشاء رمز مربّع معلومات مناسب، ثم إنشاء TileService والإشارة إليه في ملف بيان تطبيقك.

عيّنة الإعدادات السريعة: تقدّم هذه الصفحة مثالاً على كيفية إنشاء مربّع ميزة وإدارته.

إنشاء رمز مخصّص

يجب تقديم رمز مخصّص يظهر على المربّع في لوحة "الإعدادات السريعة". (ستضيف هذا الرمز عند الإفصاح عن TileService، описанном в следующем разделе.) يجب أن يكون الرمز أبيض خالصًا مع خلفية شفافة، وأن يكون أبعاده 24 x ‏24dp، وأن يكون على شكل 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

بالإضافة إلى وظائف الاستدعاء التي تتحكّم في دورة حياة الخدمة المرتبطة، عليك تنفيذ طرق أخرى خاصة بدورة حياة 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 مصبوغ ليعكس حالات العناصر
الشكل 4. أمثلة على مربّع ملوّن ليعكس حالة المربّع (الحالات النشطة وغير النشطة وغير المتوفّرة على التوالي)

تعديل مربّع معلوماتك

يمكنك تعديل مربّع معلوماتك بعد تلقّي مكالمة من فريق الدعم على الرقم onStartListening(). استنادًا إلى وضع مربّع المعلومات، يمكن تعديل مربّع المعلومات مرة واحدة على الأقل إلى أن يتمتلقّي مكالمة هاتفية إلى onStopListening().

في الوضع النشط، يمكنك تعديل مربّع العرض مرة واحدة بالضبط قبل تلقّي onStopListening(). في الوضع غير النشط، يمكنك تعديل مربّع المعلومات بقدر ما تريد بين onStartListening() وonStopListening().

يمكنك استرداد عنصر Tile من خلال الاتصال برقم getQsTile(). لتعديل حقول معيّنة من عنصر Tile، استخدِم الطريقتَين التاليتَين:

يجب استدعاء updateTile() لتعديل مربّع البيانات بعد الانتهاء من ضبط حقول عنصر Tile على القيم الصحيحة. سيؤدي ذلك إلى تحليل النظام لبيانات المربّعات المعدَّلة وتعديل واجهة المستخدم.

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 سلوكه وفقًا لذلك.

إذا كان من الآمن تنفيذ إجراء مربّع الرموز أثناء قفل الشاشة، استخدِم startActivity() لبدء نشاط على أعلى شاشة القفل.

إذا كان إجراء مربّع التطبيق غير آمن، استخدِم unlockAndRun() لطلب فتح قفل جهاز المستخدم. في حال نجاح العملية، ينفذ النظام عنصر Runnable الذي ترسله إلى هذه المحاولة.

مطالبة المستخدم بإضافة مربّعك

لإضافة مربّع العرض يدويًا، على المستخدمين اتّباع عدة خطوات:

  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 المستخدَم لاسترداد هذه الخدمة، ويجب أن يتطابق مع المستخدِم الحالي.