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

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

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

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

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

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

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

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

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

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

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

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

إنشاء مربّعك

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

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

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

ستحتاج إلى توفير رمز مخصص يظهر على المربّع في لوحة "الإعدادات السريعة". (ستتم إضافة هذا الرمز عند التعريف بميزة TileService، الموضّحة في القسم التالي). يجب أن يكون الرمز باللون الأبيض الخالص وبخلفية شفافة، وأن يكون حجمه 24 × 24 بكسل مستقل الكثافة، وأن يكون على شكل 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. بعد ذلك، يستدعي النظام معاودة الاتصال بتطبيق 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.

وضع علامة على مربّعك للإشارة إلى أنّه قابل للتبديل

نقترح عليك وضع علامة على مربّعك باعتباره قابلاً للتبديل إذا كان يعمل بشكل أساسي كمفتاح تبديل ثنائي الحالة (وهو السلوك الأكثر شيوعًا للمربّعات). يساعد هذا في توفير معلومات حول سلوك المربع إلى نظام التشغيل وتحسين إمكانية الوصول بشكل عام.

اضبط بيانات 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() لتسهّل على المستخدمين إضافة مربّعك إلى جهاز. وتطلب هذه الطريقة من المستخدمين إضافة مربّعك بسرعة مباشرةً إلى لوحة "الإعدادات السريعة". تتضمن المطالبة اسم التطبيق والتسمية المقدمة والأيقونة.

طلب من واجهة برمجة تطبيقات موضع الإعلان في الإعدادات السريعة
الشكل 5. طلب من واجهة برمجة تطبيقات موضع الإعلان في الإعدادات السريعة
public void requestAddTileService (
  ComponentName tileServiceComponentName,
  CharSequence tileLabel,
  Icon icon,
  Executor resultExecutor,
  Consumer<Integer> resultCallback
)

يحتوي رد الاتصال على معلومات حول ما إذا تمت إضافة المربع، أو عدم إضافته، أو ما إذا كانت موجودة بالفعل، أو ما إذا كان هناك أي خطأ.

الاستناد إلى تقديرك الخاص عند تحديد وقت وعدد المرات التي يجب فيها تقديم طلب إلى المستخدمين. وننصحك باستدعاء السمة requestAddTileService() فقط في السياق، مثلاً عندما يتفاعل المستخدم لأول مرة مع ميزة يسهّلها مربّعك.

يمكن أن يختار النظام إيقاف معالجة الطلبات لعنصر ComponentName معيّن إذا رفض المستخدم هذا الطلب مرات كافية من قبل. يتم تحديد المستخدم من Context المستخدمة لاسترداد هذه الخدمة، ويجب أن تتطابق مع المستخدم الحالي.