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

"الإعدادات السريعة" هي مربّعات تُعرض في لوحة "الإعدادات السريعة"، وتمثل الإجراءات التي يمكن للمستخدمين النقر عليها لإكمال المهام المتكرّرة بسرعة. يمكن أن يوفّر تطبيقك مربّعًا مخصّصًا للمستخدمين من خلال الفئة 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.

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

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

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

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

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