واجهات برمجة تطبيقات Android 4.3

مستوى واجهة برمجة التطبيقات: 18

الإصدار Android 4.3 (JELLY_BEAN_MR2) هو تحديث لإصدار Jelly Bean يقدم ميزات جديدة للمستخدمين ومطوّري التطبيقات. يقدم هذا المستند مقدمة لأهم واجهات برمجة التطبيقات الجديدة.

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

تعديل مستوى واجهة برمجة التطبيقات المستهدَف

لتحسين أداء تطبيقك على الأجهزة التي تعمل بالإصدار 4.3 من نظام التشغيل Android، عليك ضبط السمة targetSdkVersion على "18"، وتثبيتها على إحدى صور النظام التي تعمل بالإصدار 4.3 من نظام التشغيل Android، واختبارها، ثم نشر تحديث يتضمّن هذا التغيير.

يمكنك استخدام واجهات برمجة التطبيقات في Android 4.3 مع إتاحة الإصدارات الأقدم أيضًا من خلال إضافة شروط إلى الرمز البرمجي للتحقّق من مستوى واجهة برمجة تطبيقات النظام قبل تنفيذ واجهات برمجة التطبيقات غير المتوافقة مع minSdkVersion. لمعرفة المزيد حول الحفاظ على التوافق مع الأنظمة القديمة، اقرأ دعم إصدارات الأنظمة الأساسية المختلفة.

تتوفر أيضًا واجهات برمجة تطبيقات متعددة في مكتبة دعم Android تسمح لك بتنفيذ ميزات جديدة على الإصدارات القديمة من النظام الأساسي.

لمزيد من المعلومات حول طريقة عمل مستويات واجهة برمجة التطبيقات، يمكنك الاطّلاع على المقالة ما هو مستوى واجهة برمجة التطبيقات؟

تغييرات مهمة في السلوك

إذا سبق لك نشر تطبيق لنظام التشغيل Android، يُرجى العلم بأنّ تطبيقك قد يتأثر بالتغييرات في الإصدار 4.3 من نظام التشغيل Android.

في حال كان تطبيقك يستخدم أهدافًا ضمنية...

قد لا يعمل تطبيقك في بيئة ملف شخصي مقيدة.

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

عند استخدام هدف ضمني، يجب التأكد دائمًا من أنّ التطبيق متاح للتعامل مع الغرض من خلال الاتصال بالرقم resolveActivity() أو queryIntentActivities(). مثلاً:

Kotlin

val intent = Intent(Intent.ACTION_SEND)
...
if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
} else {
    Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show()
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);
...
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
} else {
    Toast.makeText(context, R.string.app_not_available, Toast.LENGTH_LONG).show();
}

إذا كان تطبيقك يعتمد على الحسابات...

قد لا يعمل تطبيقك في بيئة ملف شخصي مقيدة.

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

إذا أردت منع الملفات الشخصية المحظورة من استخدام تطبيقك بالكامل لأنّ تطبيقك يعتمد على معلومات الحساب الحسّاسة، حدِّد السمة android:requiredAccountType في عنصر <application> البيان.

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

إذا كان تطبيقك يستخدم VideoView...

قد يظهر الفيديو بحجم أصغر على Android 4.3.

في الإصدارات السابقة من نظام التشغيل Android، احتسبت أداة VideoView بشكل غير صحيح قيمة "wrap_content" للسمة layout_height وlayout_width لتكون القيمة نفسها للسمة "match_parent". ولذلك قد يكون استخدام "wrap_content" للارتفاع أو العرض قد يوفّر تنسيق الفيديو الذي تريده سابقًا، إلا أنّ ذلك قد يؤدي إلى عرض فيديو أصغر بكثير على الإصدار 4.3 من نظام التشغيل Android والإصدارات الأحدث. لحلّ المشكلة، يجب استبدال "wrap_content" بـ "match_parent" والتأكّد من ظهور الفيديو كما هو متوقّع على الإصدار 4.3 من Android والإصدارات الأقدم.

الملفات الشخصية المحظورة

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

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

وفي طريقة onReceive() من BroadcastReceiver، عليك إنشاء RestrictionEntry لكل قيد يوفّره تطبيقك. يحدّد كل RestrictionEntry عنوانًا ووصفًا للحظر وأحد أنواع البيانات التالية:

  • TYPE_BOOLEAN للقيود التي تكون "صحيح" أو "خطأ".
  • TYPE_CHOICE للقيود التي تتضمّن خيارات متعددة لا يمكن استخدامها بشكل متبادل (خيارات أزرار الاختيار).
  • TYPE_MULTI_SELECT لقيود تتضمّن خيارات متعددة ولا لا يمكن استخدامها بشكل متبادل (اختيارات في مربّعات الاختيار).

يمكنك بعد ذلك وضع جميع عناصر RestrictionEntry في ArrayList ووضعها في نتيجة مستقبِل البث كقيمة EXTRA_RESTRICTIONS_LIST الإضافية.

ينشئ النظام واجهة المستخدم للقيود المفروضة على تطبيقك في تطبيق "الإعدادات"، ويحفظ كل قيد باستخدام المفتاح الفريد الذي قدّمته لكل كائن RestrictionEntry. عندما يفتح المستخدم تطبيقك، يمكنك طلب الاطّلاع على أي قيود حالية من خلال الاتصال على getApplicationRestrictions(). يؤدي ذلك إلى عرض Bundle يحتوي على أزواج المفتاح/القيمة لكل قيد حددته باستخدام كائنات RestrictionEntry.

إذا كنت تريد وضع قيود أكثر تحديدًا لا يمكن التعامل معها باستخدام القيم المنطقية، وقيم الاختيار الفردي، والقيم المتعددة الخيارات، يمكنك عندئذٍ إنشاء نشاط يمكن للمستخدم فيه تحديد القيود والسماح للمستخدمين بفتح هذا النشاط من إعدادات القيود. في جهاز استقبال البث، ضمِّن EXTRA_RESTRICTIONS_INTENT الإضافي في النتيجة Bundle. يجب أن تحدد هذه السمة الإضافية Intent تشير إلى بدء الفئة Activity (استخدِم طريقة putParcelable() لتمرير EXTRA_RESTRICTIONS_INTENT باستخدام الغرض). عندما يُدخل المستخدم الأساسي نشاطك لضبط قيود مخصّصة، يجب أن يعرض نشاطك نتيجة تحتوي على قيم القيود في عنصر إضافي باستخدام المفتاح EXTRA_RESTRICTIONS_LIST أو EXTRA_RESTRICTIONS_BUNDLE، وذلك بناءً على ما إذا كنت تحدّد كائنات RestrictionEntry أو أزواج المفتاح/القيمة، على التوالي.

دعم الحسابات في ملف شخصي مقيَّد

وتكون أي حسابات مُضافة إلى المستخدم الأساسي متاحة في ملف شخصي محدود، ولكن لا يمكن الوصول إلى الحسابات من خلال واجهات برمجة تطبيقات AccountManager تلقائيًا. إذا حاولت إضافة حساب باستخدام AccountManager في ملف شخصي مقيَّد، ستظهر لك نتيجة تعذُّر تنفيذ العملية. نتيجةً لهذه القيود، تتوفّر لك الخيارات الثلاثة التالية:

  • السماح بالوصول إلى حسابات المالك من ملف شخصي مقيَّد

    للوصول إلى حساب من ملف شخصي محدود، عليك إضافة السمة android:restrictedAccountType إلى العلامة <Application>:

    <application ...
        android:restrictedAccountType="com.example.account.type" >
    

    تنبيه: يؤدي تفعيل هذه السمة إلى توفير إمكانية وصول تطبيقك إلى حسابات المستخدم الأساسي من الملفات الشخصية المحظورة. لذا يجب عدم السماح بذلك إلا إذا كانت المعلومات التي يعرضها تطبيقك لا تكشف عن معلومات تحديد الهوية الشخصية (PII) التي تعتبر حسّاسة. ستُعلِم إعدادات النظام المستخدم الأساسي بأنّ تطبيقك يمنح ملفات شخصية مقيَّدة لحساباته، لذا يجب أن يكون واضحًا للمستخدم أنّ الوصول إلى الحساب مهم لوظائف التطبيق. عليك أيضًا توفير عناصر تحكّم كافية في القيود للمستخدِم الأساسي تحدِّد مقدار الوصول المسموح به إلى الحساب في تطبيقك، إن أمكن ذلك.

  • إيقاف وظائف معيّنة عندما يتعذّر تعديل الحسابات

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

    Kotlin

    val um = context.getSystemService(Context.USER_SERVICE) as UserManager
    val restrictions: Bundle = um.userRestrictions
    if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
        // cannot add accounts, disable some functionality
    }
    

    Java

    UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
    Bundle restrictions = um.getUserRestrictions();
    if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) {
        // cannot add accounts, disable some functionality
    }
    

    ملاحظة: في هذا السيناريو، يجب عدم الإفصاح عن أي سمات جديدة في ملف البيان.

  • إيقاف تطبيقك عندما يتعذّر عليك الوصول إلى الحسابات الخاصة

    إذا كان من المهم بدلاً من ذلك ألا يكون تطبيقك متاحًا للملفات الشخصية المحظورة لأنّ تطبيقك يعتمد على معلومات شخصية حسّاسة في الحساب (ولأن الملفات الشخصية المحظورة لا يمكنها حاليًا إضافة حسابات جديدة)، أضِف السمة android:requiredAccountType إلى علامة <تطبيق>:

    <application ...
        android:requiredAccountType="com.example.account.type" >
    

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

  • اللاسلكي وإمكانية الاتصال

    بلوتوث منخفض الطاقة (إعداد ذكي)

    يتيح نظام Android الآن استخدام البلوتوث المنخفض الطاقة (LE) من خلال واجهات برمجة التطبيقات الجديدة في android.bluetooth. باستخدام واجهات برمجة التطبيقات الجديدة، يمكنك إنشاء تطبيقات Android تتصل بالأجهزة الطرفية التي تعمل بالبلوتوث منخفض الطاقة مثل أجهزة مراقبة معدل ضربات القلب وأجهزة قياس الخطوات.

    بما أنّ ميزة Bluetooth LE هي ميزة في الجهاز ولكنّها غير متوفّرة على جميع الأجهزة التي تعمل بنظام التشغيل Android، يجب الإشارة في ملف البيان إلى أنّه يتضمّن العنصر <uses-feature> في "android.hardware.bluetooth_le":

    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
    

    إذا كنت على دراية بواجهات برمجة تطبيقات البلوتوث الكلاسيكية في نظام التشغيل Android، يمكنك ملاحظة أنّ استخدام واجهات برمجة تطبيقات Bluetooth LE API له بعض الاختلافات. والأهم من ذلك أنّه يتوفّر الآن فئة BluetoothManager يجب استخدامها في بعض العمليات العالية المستوى، مثل الحصول على BluetoothAdapter والحصول على قائمة بالأجهزة المتصلة والتحقق من حالة أحد الأجهزة. على سبيل المثال، إليك خطوات الحصول على BluetoothAdapter:

    Kotlin

    val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    bluetoothAdapter = bluetoothManager.adapter
    

    Java

    final BluetoothManager bluetoothManager =
            (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
    bluetoothAdapter = bluetoothManager.getAdapter();
    

    لاكتشاف الأجهزة الملحقة التي تعمل بتكنولوجيا Bluetooth LE، يمكنك الاتصال بالرقم startLeScan() على BluetoothAdapter، وسيتم تمريرها من خلال تنفيذ واجهة BluetoothAdapter.LeScanCallback. عندما يرصد محوّل البلوتوث جهازًا ملحقًا يتضمّن تقنية البلوتوث منخفض الطاقة، يتلقّى جهاز تنفيذ BluetoothAdapter.LeScanCallback اتصالاً بطريقة onLeScan(). وتزوِّدك هذه الطريقة بكائن BluetoothDevice يمثّل الجهاز الذي تم رصده، وقيمة RSSI للجهاز، ومصفوفة بايت تتضمّن سجلّ إعلانات الجهاز.

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

    ملاحظة: يمكنك البحث عن أجهزة Bluetooth LE فقط أو البحث عن أجهزة Bluetooth الكلاسيكية باستخدام واجهات برمجة التطبيقات السابقة. لا يمكنك البحث عن أجهزة Bluetooth LE وكلاسيكية في وقت واحد.

    للاتصال بعد ذلك بجهاز ملحق مزوّد بتقنية Bluetooth LE، استدعِ connectGatt() على الكائن BluetoothDevice المقابل، واضبطه على تنفيذ BluetoothGattCallback. تتلقّى عمليات تنفيذ BluetoothGattCallback استدعاءات بشأن حالة الاتصال بالجهاز والأحداث الأخرى. أثناء معاودة الاتصال بـ "onConnectionStateChange()"، يمكنك بدء الاتصال بالجهاز إذا اجتازت الطريقة STATE_CONNECTED باعتباره الحالة الجديدة.

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

    وضع البحث عن شبكات Wi-Fi فقط

    عند محاولة تحديد الموقع الجغرافي للمستخدم، قد يستخدم Android شبكة Wi-Fi للمساعدة في تحديد الموقع الجغرافي من خلال البحث عن نقاط وصول قريبة. ومع ذلك، غالبًا ما يحافظ المستخدمون على إيقاف تشغيل شبكة Wi-Fi للحفاظ على البطارية، ما يؤدي إلى ظهور بيانات موقع أقل دقة. يشمل Android الآن وضع "المسح الضوئي فقط" الذي يتيح لشبكة Wi-Fi في الجهاز فحص نقاط الوصول من أجل المساعدة في الحصول على الموقع الجغرافي بدون الاتصال بنقطة وصول، ما يؤدي إلى تقليل استخدام البطارية بشكل كبير.

    إذا كنت تريد معرفة الموقع الجغرافي للمستخدم ولكن شبكة Wi-Fi غير مفعّلة حاليًا، يمكنك أن تطلب من المستخدم تفعيل وضع البحث عن شبكات Wi-Fi فقط من خلال استدعاء startActivity() مع الإجراء ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE.

    إعدادات Wi-Fi

    تسمح واجهات برمجة التطبيقات WifiEnterpriseConfig الجديدة للخدمات الموجَّهة للمؤسسات بتفعيل إعدادات Wi-Fi تلقائيًا للأجهزة المُدارة.

    الردّ السريع على المكالمات الواردة

    منذ Android 4.0، تتيح ميزة "الاستجابة السريعة" للمستخدمين الرد على المكالمات الواردة برسالة نصية فورية بدون الحاجة إلى الرد على المكالمة أو فتح قفل الجهاز. حتى الآن، كان تطبيق المراسلة التلقائي يتعامل دائمًا مع هذه الرسائل السريعة. والآن يمكن لأي تطبيق الإفصاح عن قدرته على التعامل مع هذه الرسائل من خلال إنشاء Service باستخدام فلتر أهداف لـ ACTION_RESPOND_VIA_MESSAGE.

    عندما يردّ المستخدم على مكالمة واردة باستخدام ردّ سريع، يرسل تطبيق "الهاتف" هدف ACTION_RESPOND_VIA_MESSAGE مع معرّف موارد منتظم (URI) يصف المستلِم (المتصل) وEXTRA_TEXT الرقم الإضافي مع الرسالة التي يريد المستخدم إرسالها. عندما تتلقّى خدمتك الغرض، من المفترض أن توصل الرسالة وتتوقف فورًا عن نفسها (يجب ألا يعرض التطبيق أي نشاط).

    لتحقيق هذا الغرض، يجب تقديم بيان عن إذن SEND_RESPOND_VIA_MESSAGE.

    وسائط متعددة

    تحسينات Mediaاستخراجor وMediaCodec

    سيسهّل عليك Android الآن كتابة محتوى البث الديناميكي التكيُّفي عبر مشغّلات HTTP (DASH) بما يتوافق مع معيار ISO/IEC 23009-1، باستخدام واجهات برمجة التطبيقات الحالية في MediaCodec وMediaExtractor. تم تعديل إطار العمل الذي يستند إلى واجهات برمجة التطبيقات هذه لإتاحة تحليل ملفات MP4 المجزأة، ولكن لا يزال تطبيقك مسؤولاً عن تحليل بيانات MPD الوصفية وتمرير عمليات البث الفردية إلى MediaExtractor.

    إذا أردت استخدام DASH مع المحتوى المشفّر، يُرجى العِلم أنّ الطريقة getSampleCryptoInfo() تعرض البيانات الوصفية MediaCodec.CryptoInfo التي تصف بنية كل عيّنة من الوسائط المشفّرة. أُضيفت أيضًا الطريقة getPsshInfo() إلى MediaExtractor لتتمكّن من الوصول إلى بيانات PSSH الوصفية لوسائط DASH. تعرض هذه الطريقة خريطة من كائنات UUID إلى وحدات بايت، حيث يحدّد UUID مخطط عملات التشفير، وأن تكون وحدات البايت هي البيانات الخاصة بهذا المخطط.

    إدارة الحقوق الرقمية للوسائط

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

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

    تم تصميم واجهات برمجة التطبيقات MediaDrm للاستخدام بالاقتران مع واجهات برمجة التطبيقات MediaCodec التي تم تقديمها في الإصدار Android 4.1 (المستوى 16 من واجهة برمجة التطبيقات)، بما في ذلك MediaCodec لترميز المحتوى وفك ترميزه، وMediaCrypto للتعامل مع المحتوى المشفّر، وMediaExtractor لاستخراج المحتوى وإزالة تشويشه.

    يجب أولاً إنشاء كائنات MediaExtractor وMediaCodec. يمكنك بعد ذلك الوصول إلى علامة UUID المحدِّدة لمخطّط DRM من خلال البيانات الوصفية في المحتوى عادةً، واستخدامها لإنشاء مثيل لكائن MediaDrm باستخدام الدالة الإنشائية له.

    ترميز الفيديو من أحد أسطح

    أضاف نظام التشغيل Android 4.1 (المستوى 16 من واجهة برمجة التطبيقات) الفئة MediaCodec لترميز محتوى الوسائط وفك ترميزه المنخفض المستوى. أثناء ترميز الفيديو، كان نظام التشغيل Android 4.1 يتطلب منك تزويد الوسائط بمصفوفة ByteBuffer، غير أنّ الإصدار 4.3 من نظام التشغيل Android يتيح لك الآن استخدام Surface كإدخال لبرنامج ترميز. على سبيل المثال، يتيح لك ذلك ترميز الإدخال من ملف فيديو حالي أو استخدام إطارات تم إنشاؤها من OpenGL ES.

    لاستخدام Surface كإدخال لبرنامج الترميز، يجب أولاً الاتصال بـ configure() على جهاز MediaCodec. يمكنك بعد ذلك الاتصال بـ createInputSurface() لتلقّي Surface التي يمكنك من خلالها بث الوسائط.

    على سبيل المثال، يمكنك استخدام علامة Surface المحدّدة كنافذة لسياق OpenGL من خلال تمريرها إلى eglCreateWindowSurface(). بعد ذلك، أثناء عرض السطح، عليك طلب الرمز eglSwapBuffers() لتمرير الإطار إلى MediaCodec.

    لبدء عملية الترميز، يُرجى طلب "start()" على "MediaCodec". عند الانتهاء، استدعِ signalEndOfInputStream() لإنهاء الترميز، واستدعِ release() على Surface.

    دمج الوسائط

    تتيح الفئة MediaMuxer الجديدة تعدد الإرسال بين بث صوتي واحد وبث فيديو واحد. وتعمل واجهات برمجة التطبيقات هذه كنظير للفئة MediaExtractor التي تمّت إضافتها في Android 4.2 لإزالة تعدد الإرسال (إزالة التشويش).

    يتم تحديد تنسيقات الإخراج المتوافقة باللغة MediaMuxer.OutputFormat. في الوقت الحالي، MP4 هو تنسيق الإخراج الوحيد المتاح، ويتوافق MediaMuxer حاليًا مع بث صوتي واحد و/أو بث فيديو واحد فقط في كل مرة.

    تم تصميم MediaMuxer بشكل أساسي للعمل مع MediaCodec، ما يتيح لك معالجة الفيديو من خلال MediaCodec ثم حفظ الناتج في ملف MP4 من خلال MediaMuxer. يمكنك أيضًا استخدام MediaMuxer مع MediaExtractor لإجراء تعديل للوسائط بدون الحاجة إلى ترميز أو فك ترميز.

    تقدُّم التشغيل وتنقيح البيانات في RemoteControlClient

    في نظام التشغيل Android 4.0 (المستوى 14 من واجهة برمجة التطبيقات)، تمت إضافة RemoteControlClient لتفعيل عناصر التحكّم في تشغيل الوسائط من برامج التحكّم عن بُعد مثل عناصر التحكّم المتوفّرة على شاشة القفل. أما الآن، نظام التشغيل Android 4.3 فهو يتيح لوحدات التحكم هذه عرض موضع التشغيل وعناصر التحكم في التقديم والترجيع أثناء التشغيل. إذا فعّلت التحكّم عن بُعد لتطبيق الوسائط الخاص بك باستخدام واجهات برمجة التطبيقات RemoteControlClient، يمكنك حينئذٍ السماح بالتمرير السريع للتشغيل من خلال تطبيق واجهتَين جديدتَين.

    أولاً، يجب تفعيل علامة FLAG_KEY_MEDIA_POSITION_UPDATE من خلال تمريرها إلى setTransportControlsFlags().

    بعد ذلك، نفِّذ الواجهتين الجديدتين التاليتين:

    RemoteControlClient.OnGetPlaybackPositionListener
    يشمل ذلك خيار معاودة الاتصال onGetPlaybackPosition() الذي يطلب الموضع الحالي للوسائط عندما تحتاج وحدة التحكّم عن بُعد إلى تعديل مستوى التقدّم في واجهة المستخدم الخاصة بها.
    RemoteControlClient.OnPlaybackPositionUpdateListener
    يشمل ذلك رمز معاودة الاتصال onPlaybackPositionUpdate() الذي يحدّد لتطبيقك الرمز الزمني الجديد للوسائط عندما يفسّر المستخدم التشغيل باستخدام واجهة المستخدم لوحدة التحكّم عن بُعد.

    بعد تعديل موضع التشغيل الجديد، يمكنك استدعاء setPlaybackState() للإشارة إلى حالة التشغيل والموضع والسرعة الجديدة.

    بعد تحديد هاتين الواجهتين، يمكنك إعدادهما لـ RemoteControlClient من خلال استدعاء setOnGetPlaybackPositionListener() وsetPlaybackPositionUpdateListener() على التوالي.

    الرسومات

    التوافق مع OpenGL ES 3.0

    يضيف نظام التشغيل Android 4.3 واجهات Java ودعمًا أصليًا لبرنامج OpenGL ES 3.0. تشمل الوظائف الأساسية الجديدة التي يوفّرها OpenGL ES 3.0 ما يلي:

    • تسريع التأثيرات المرئية المتقدّمة
    • ضغط بنية ETC2/EAC عالي الجودة كميزة عادية
    • إصدار جديد من لغة تظليل GLSL ES مع عدد صحيح ونقطة عائمة 32 بت
    • عرض محسّن للزخرفة
    • توحيد حجم القوام وتنسيقات المخزن المؤقت للعرض على نطاق أوسع

    يتم توفير واجهة Java لبرنامج OpenGL ES 3.0 على نظام التشغيل Android مع GLES30. عند استخدام OpenGL ES 3.0، احرص على الإعلان عنه في ملف البيان باستخدام العلامة <uses-feature> والسمة android:glEsVersion. مثلاً:

    <manifest>
        <uses-feature android:glEsVersion="0x00030000" />
        ...
    </manifest>
    

    وتذكّر تحديد سياق OpenGL ES من خلال طلب setEGLContextClientVersion()، مع ضبط 3 كإصدار.

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

    دمج الموسيقى مع العناصر القابلة للرسم

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

    أتاح نظام Android 4.2 (المستوى 17 من واجهة برمجة التطبيقات) استخدام خرائط mipmaps في الفئة Bitmap. يعمل Android على تبديل صور mip في Bitmap عند توفير مصدر mipmap وتفعيل setHasMipMap(). يمكنك الآن في Android 4.3 تفعيل خرائط mipmaps لكائن BitmapDrawable أيضًا، من خلال توفير مادة عرض mipmap وتعيين السمة android:mipMap في ملف مورد صورة نقطية أو من خلال استدعاء hasMipMap().

    واجهة المستخدم

    عرض التراكبات

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

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

    عند إنشاء تراكب لعرض أدوات مثل Button، يمكنك إضافة كائنات Drawable إلى التراكب عن طريق طلب add(Drawable). إذا استدعيت getOverlay() لعرض تنسيق، مثل RelativeLayout، يكون الكائن الذي يتم عرضه ViewGroupOverlay. الفئة ViewGroupOverlay هي فئة فرعية من ViewOverlay تسمح لك أيضًا بإضافة كائنات View عن طريق استدعاء add(View).

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

    على سبيل المثال، تحرّك الكود التالي طريقة عرض انزلاقها إلى اليمين من خلال وضع العرض في تراكب طريقة العرض الرئيسية، ثم تنفيذ رسم متحرك للترجمة في هذا العرض:

    Kotlin

    val view: View? = findViewById(R.id.view_to_remove)
    val container: ViewGroup? = view?.parent as ViewGroup
    
    container?.apply {
        overlay.add(view)
        ObjectAnimator.ofFloat(view, "translationX", right.toFloat())
                .start()
    }
    

    Java

    View view = findViewById(R.id.view_to_remove);
    ViewGroup container = (ViewGroup) view.getParent();
    container.getOverlay().add(view);
    ObjectAnimator anim = ObjectAnimator.ofFloat(view, "translationX", container.getRight());
    anim.start();
    

    تخطيط الحدود البصرية

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

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

    ملاحظة: لقطة الشاشة في الشكلين 1 و2 بها إعداد مطوّر البرامج "إظهار حدود التنسيق" مُفعَّل. لكل طريقة عرض، تشير الخطوط الحمراء إلى الحدود البصرية، وتشير الخطوط الزرقاء إلى حدود المقطع، وتشير الخطوط الوردية إلى الهوامش.

    الشكل 1. تنسيق باستخدام حدود المقطع (تلقائي).

    الشكل 2. تخطيط باستخدام الحدود البصرية.

    لمحاذاة طرق العرض استنادًا إلى حدودها البصرية، اضبط السمة android:layoutMode على "opticalBounds" في أحد التنسيقات الرئيسية. مثلاً:

    <LinearLayout android:layoutMode="opticalBounds" ... >
    

    الشكل 3. عرض مُكبَّر للزر "هولو" من تسعة رقعة مع حدود بصرية.

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

    عند تفعيل الحدود البصرية لـ ViewGroup في تنسيقك، تكتسِب جميع طرق العرض التابعة وضع تنسيق الحدود البصرية ما لم تستبدِله لمجموعة من خلال ضبط android:layoutMode على "clipBounds". تلتزم جميع عناصر التصميم أيضًا بالحدود البصرية لطرق العرض الفرعية الخاصة بها، وتكييف حدودها على أساس الحدود البصرية للعروض المتوفّرة بداخلها. ومع ذلك، لا تتوافق عناصر التنسيق (الفئات الفرعية من ViewGroup) حاليًا مع الحدود البصرية للصور التي تتضمّن تسعة تصحيحات ويتم تطبيقها على الخلفية الخاصة بها.

    في حال إنشاء طريقة عرض مخصّصة من خلال التصنيف الفرعي View أو ViewGroup أو أي فئات فرعية منها، سيكتسب الملف الشخصي هذه السلوكيات المرتبطة البصري.

    ملاحظة: تم تحديث جميع التطبيقات المصغّرة المتوافقة مع مظهر Holo باستخدام حدود بصرية، بما في ذلك Button وSpinner وEditText وغير ذلك. لكي تستفيد فورًا من هذه السمة من خلال ضبط السمة android:layoutMode على "opticalBounds" إذا كان تطبيقك يطبّق مظهر Holo (Theme.Holo، وTheme.Holo.Light، وغير ذلك).

    لتحديد الحدود البصرية لصورك المكوَّنة من تسعة رقاقات باستخدام أداة الرسم 9-بات، اضغط مع الاستمرار على زر التحكّم عند النقر على وحدات بكسل الحدود.

    مؤثرات حركية لقيم المستطيل

    يمكنك الآن إضافة تأثير متحرك بين قيمتَي Rect باستخدام السمة RectEvaluator الجديدة. هذا الصف الجديد هو تنفيذ لـ TypeEvaluator يمكنك تمريره إلى ValueAnimator.setEvaluator().

    تثبيت النافذة والتركيز على أداة المستمع

    في السابق، إذا كنت تريد الاستماع إلى الصوت عندما يتم إرفاق/فصل العرض بالنافذة أو عند تغيير التركيز، كان عليك إلغاء الفئة View لتنفيذ الترميزَين onAttachedToWindow() وonDetachedFromWindow()، أو onWindowFocusChanged() على التوالي.

    الآن، لتلقّي إرفاق الأحداث وفصلها، يمكنك بدلاً من ذلك تطبيق ViewTreeObserver.OnWindowAttachListener وضبطه على ملف شخصي باستخدام addOnWindowAttachListener(). ولتلقّي أحداث التركيز، يمكنك تنفيذ علامة ViewTreeObserver.OnWindowFocusChangeListener وضبطها على طريقة عرض باستخدام addOnWindowFocusChangeListener().

    إتاحة الخروج عن إطار الشاشة على التلفزيون

    للتأكّد من أنّ تطبيقك يملأ الشاشة بأكملها على كل تلفزيون، يمكنك الآن تفعيل ميزة "الإفراط في المسح الضوئي" لتطبيقك على تنسيق تطبيقك. يتم تحديد وضع الخروج عن إطار الشاشة من خلال علامة FLAG_LAYOUT_IN_OVERSCAN التي يمكنك تفعيلها باستخدام مظاهر النظام الأساسي مثل Theme_DeviceDefault_NoActionBar_Overscan أو من خلال تفعيل النمط windowOverscan في مظهر مخصّص.

    اتجاه الشاشة

    توفِّر سمة العلامة <activity> screenOrientation الآن قيمًا إضافية لتلبية خيار المستخدم المفضّل للتناوب التلقائي:

    "userLandscape"
    يتصرف مثل "sensorLandscape"، إلا إذا أوقف المستخدم ميزة التدوير التلقائي، سيتم تثبيت الجهاز في الاتجاه الأفقي العادي ولن يؤدي إلى قلب العدسة.
    "userPortrait"
    يتصرف مثل "sensorPortrait"، إلا إذا أوقف المستخدم التدوير التلقائي، سيتم تثبيت الجهاز في الاتجاه العمودي الطبيعي ولن يتم قلب الجهاز.
    "fullUser"
    يتصرف مثل "fullSensor" ويسمح بالتدوير في جميع الاتجاهات الأربعة، إلا إذا أوقف المستخدم التدوير التلقائي، حينئذٍ يتم قفله في الاتجاه الذي يفضله المستخدم.

    بالإضافة إلى ذلك، يمكنك الآن أيضًا تقديم بيان عن "locked" لقفل اتجاه التطبيق في الاتجاه الحالي للشاشة.

    الصور المتحركة التي يتم تدويرها

    يسمح لك حقل rotationAnimation الجديد في WindowManager بالاختيار من بين ثلاث صور متحركة تريد استخدامها عندما يبدّل النظام اتجاهات الشاشة. الرسوم المتحركة الثلاثة هي:

    ملاحظة: لا تتوفر هذه الصور المتحركة إلا إذا ضبطت نشاطك على استخدام وضع "ملء الشاشة"، والذي يمكنك تفعيله مع مظاهر مثل Theme.Holo.NoActionBar.Fullscreen.

    على سبيل المثال، في ما يلي كيفية تفعيل الصورة المتحركة "التلاشي المتقاطع":

    Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val params: WindowManager.LayoutParams = window.attributes
        params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE
        window.attributes = params
        ...
    }
    

    Java

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
        getWindow().setAttributes(params);
        ...
    }
    

    إدخال المستخدم

    أنواع أدوات الاستشعار الجديدة

    تتيح لك أداة الاستشعار الجديدة "TYPE_GAME_ROTATION_VECTOR" اكتشاف دوران الجهاز بدون القلق بشأن التداخل المغناطيسي. على عكس أداة استشعار TYPE_ROTATION_VECTOR، لا يعتمد جهاز TYPE_GAME_ROTATION_VECTOR على الشمال المغناطيسي.

    توفِّر أدوات الاستشعار TYPE_GYROSCOPE_UNCALIBRATED وTYPE_MAGNETIC_FIELD_UNCALIBRATED الجديدة بيانات أداة الاستشعار الأولية بدون مراعاة تقديرات الانحياز. ويعني ذلك أنّ المستشعرَين TYPE_GYROSCOPE وTYPE_MAGNETIC_FIELD الحاليَّين يوفران بيانات أداة الاستشعار التي تأخذ في الاعتبار الانحياز المقدَّر بسبب انحرف الجيروسكوب والحديد الصلب في الجهاز على التوالي. بينما توفر الإصدارات الجديدة "غير المعايرة" من أدوات الاستشعار هذه بيانات أداة الاستشعار الأولية وتعرض قيم الانحياز المقدّرة بشكل منفصل. وتتيح لك أدوات الاستشعار هذه إجراء معايرة مخصّصة خاصة بك لبيانات أداة الاستشعار من خلال زيادة مقدار الانحياز المقدَّر باستخدام البيانات الخارجية.

    Notification Listener

    يضيف نظام التشغيل Android 4.3 فئة خدمة جديدة، وهي NotificationListenerService، تسمح لتطبيقك بتلقّي معلومات حول الإشعارات الجديدة فور نشرها من خلال النظام.

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

    مقدِّم جهات الاتصال

    طلب بحث عن "العناصر القابلة للاتصال"

    يوفّر طلب البحث الجديد لمقدّمي خدمة جهات الاتصال، Contactables.CONTENT_URI، طريقة فعّالة للحصول على رقم Cursor واحد يحتوي على جميع عناوين البريد الإلكتروني وأرقام الهواتف التي تنتمي إلى جميع جهات الاتصال المطابقة لطلب البحث المحدّد.

    طلب بحث عن قيم دلتا لجهات الاتصال

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

    لتتبُّع التغييرات التي تطرأ على عمليات الإدراج والتحديثات، يمكنك الآن تضمين المَعلمة CONTACT_LAST_UPDATED_TIMESTAMP مع اختيارك لإجراء طلب بحث فقط عن جهات الاتصال التي تم تغييرها منذ آخر مرة أجريت فيها طلب بحث من مقدّم الخدمة.

    لتتبع جهات الاتصال التي تم حذفها، يوفر الجدول الجديد ContactsContract.DeletedContacts سجلاً لجهات الاتصال التي تم حذفها (ولكن يتم الاحتفاظ بكل جهة اتصال في هذا الجدول لفترة محدودة). على غرار CONTACT_LAST_UPDATED_TIMESTAMP، يمكنك استخدام مَعلمة الاختيار الجديدة CONTACT_DELETED_TIMESTAMP للتحقّق من جهات الاتصال التي تم حذفها منذ آخر مرة طلبت فيها من مقدّم الخدمة. يحتوي الجدول أيضًا على القيمة الثابتة DAYS_KEPT_MILLISECONDS التي تتضمّن عدد الأيام (بالمللي ثانية) التي سيتم الاحتفاظ بالسجلّ فيها.

    بالإضافة إلى ذلك، يبث "مقدِّم جهات الاتصال" الآن الإجراء CONTACTS_DATABASE_CREATED عندما يمحو المستخدم مساحة تخزين جهات الاتصال من خلال قائمة إعدادات النظام، ما يؤدي إلى إعادة إنشاء قاعدة بيانات "مقدِّم جهات الاتصال" بفعالية. الغرض منه هو إرسال إشارة إلى التطبيقات أنها بحاجة إلى إسقاط جميع معلومات الاتصال التي خزنتها وإعادة تحميلها بطلب بحث جديد.

    للحصول على نموذج رمز يستخدم واجهات برمجة التطبيقات هذه للتحقّق من التغييرات التي تطرأ على جهات الاتصال، يمكنك الاطّلاع على نموذج ApiDemos المتوفّر في تنزيل SDK عيّنات.

    الأقلمة

    دعم مُحسَّن للنص ثنائي الاتجاه

    تتوافق الإصدارات السابقة من Android مع التنسيق واللغات التي تُكتب من اليمين إلى اليسار (RTL)، ولكنها لا تتعامل أحيانًا مع النص المختلط بشكل صحيح. ولذلك، يضيف نظام التشغيل Android 4.3 واجهات برمجة التطبيقات BidiFormatter التي تساعدك في تنسيق النص بشكلٍ صحيح مع محتوى باتجاه معاكس بدون تشويه أي جزء منه.

    على سبيل المثال، عندما تريد إنشاء جملة باستخدام متغير سلسلة، مثل "هل تقصد 15 Bay Street, Laurel, CA?"، فعادةً ما يتم تمرير مورد سلسلة مترجم والمتغيّر إلى String.format():

    Kotlin

    val suggestion = String.format(resources.getString(R.string.did_you_mean), address)
    

    Java

    Resources res = getResources();
    String suggestion = String.format(res.getString(R.string.did_you_mean), address);
    

    ومع ذلك، إذا كانت اللغة العبرية، فإن السلسلة المنسقة تظهر على النحو التالي:

    فيما يلي كل الصور التي يمكن استخدامها على شبكة 15 Bay Street, Laurel, CA?

    هذا خطأ لأنه يجب ترك "15" على يسار "Bay Street". الحل هو استخدام BidiFormatter وطريقة unicodeWrap() الخاصة بها. على سبيل المثال، يصبح الرمز الوارد أعلاه:

    Kotlin

    val bidiFormatter = BidiFormatter.getInstance()
    val suggestion = String.format(
            resources.getString(R.string.did_you_mean),
            bidiFormatter.unicodeWrap(address)
    )
    

    Java

    Resources res = getResources();
    BidiFormatter bidiFormatter = BidiFormatter.getInstance();
    String suggestion = String.format(res.getString(R.string.did_you_mean),
            bidiFormatter.unicodeWrap(address));
    

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

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

    خدمات تسهيل الاستخدام

    التعامل مع الأحداث الرئيسية

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

    تحديد النص والنسخ/اللصق

    توفّر "AccessibilityNodeInfo" الآن واجهات برمجة تطبيقات تتيح لـ AccessibilityService اختيار النص وقصه ونسخه ولصقه في عقدة.

    لتحديد النص الذي تريد قصه أو نسخه، يمكن لخدمة تسهيل الاستخدام استخدام الإجراء الجديد، ACTION_SET_SELECTION، مع تمرير معه موضعي البداية والنهاية بالرمزين ACTION_ARGUMENT_SELECTION_START_INT وACTION_ARGUMENT_SELECTION_END_INT. يمكنك بدلاً من ذلك اختيار النص من خلال معالجة موضع المؤشر باستخدام الإجراء الحالي ACTION_NEXT_AT_MOVEMENT_GRANULARITY (كان سابقًا لتحريك موضع المؤشر فقط) وإضافة الوسيطة ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN.

    يمكنك بعد ذلك قصها أو نسخها باستخدام ACTION_CUT وACTION_COPY، ثم اللصق لاحقًا باستخدام ACTION_PASTE.

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

    الإفصاح عن ميزات تسهيل الاستخدام

    بدايةً من الإصدار 4.3 من نظام التشغيل Android، يجب أن تذكر الخدمة المخصصة لتسهيل الاستخدام ميزات تسهيل الاستخدام في ملف البيانات الوصفية من أجل استخدام بعض ميزات تسهيل الاستخدام. وإذا لم تكن هذه الميزة مطلوبة في ملف البيانات الوصفية، ستكون الميزة غير مفعّلة. للإعلان عن إمكانات تسهيل الاستخدام في خدمتك، عليك استخدام سمات XML التي تتوافق مع ثوابت "القدرات" المختلفة في الفئة AccessibilityServiceInfo.

    على سبيل المثال، إذا لم تطلب الخدمة إمكانية "flagRequestFilterKeyEvents"، لن تتلقّى الأحداث الرئيسية.

    الاختبار وتصحيح الأخطاء

    اختبار مبرمَج لواجهة المستخدم

    توفّر الفئة UiAutomation الجديدة واجهات برمجة تطبيقات تتيح لك محاكاة إجراءات المستخدم من أجل التشغيل الآلي للاختبار. باستخدام واجهات برمجة التطبيقات AccessibilityService الخاصة بالنظام الأساسي، تسمح لك واجهات برمجة التطبيقات UiAutomation بفحص محتوى الشاشة وإدخال أحداث عشوائية لوحة المفاتيح واللمس.

    للحصول على نسخة افتراضية من "UiAutomation"، يمكنك استدعاء "Instrumentation.getUiAutomation()". لتنفيذ ذلك، عليك توفير الخيار -w مع الأمر instrument عند تشغيل InstrumentationTestCase من adb shell.

    باستخدام مثيل UiAutomation، يمكنك تنفيذ أحداث عشوائية لاختبار تطبيقك من خلال استدعاء executeAndWaitForEvent()، ومنحه Runnable لتنفيذه، ومهلة عملية للعملية، وتنفيذ واجهة UiAutomation.AccessibilityEventFilter. ضمن عملية تنفيذ UiAutomation.AccessibilityEventFilter، ستتلقّى مكالمة تتيح لك فلترة الأحداث التي تهمّك وتحديد مدى نجاح أو تعذُّر حالة اختبار معيّنة.

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

    هناك مجموعة متنوّعة من العمليات الأخرى التي تعرضها واجهات برمجة تطبيقات UiAutomation على مستوى منخفض جدًا لتشجيع تطوير أدوات اختبار واجهة المستخدم مثل uiautomator. على سبيل المثال، يمكنك أيضًا استخدام "UiAutomation" لتنفيذ ما يلي:

    • إدخال أحداث الإدخال
    • تغيير اتجاه الشاشة
    • أخذ لقطات شاشة

    والأهم من ذلك أنّه في أدوات اختبار واجهة المستخدم، تعمل واجهات برمجة التطبيقات UiAutomation على مستوى التطبيقات المختلفة، على عكس Instrumentation.

    أحداث Systrace للتطبيقات

    يضيف نظام التشغيل Android 4.3 الفئة Trace بطريقتين ثابتتين، beginSection() وendSection()، اللذين يسمحان لك بتحديد كتل الرموز المراد تضمينها في تقرير systrace. ومن خلال إنشاء أقسام من الرموز البرمجية القابلة للتتبُّع في تطبيقك، توفّر لك سجلات systrace تحليلاً أكثر تفصيلاً لمكان حدوث تباطؤ في تطبيقك.

    وللحصول على معلومات عن استخدام أداة Systrace، اقرأ تحليل العرض والأداء باستخدام Systrace.

    الأمان

    ملف تخزين مفاتيح Android للمفاتيح الخاصة بالتطبيقات

    يوفّر Android الآن "موفِّر أمان JavaScript مخصّصًا" في منشأة KeyStore، تُسمى "متجر مفاتيح Android"، وهي تتيح لك إنشاء وحفظ مفاتيح خاصة يمكن لتطبيقك الاطّلاع عليها واستخدامها فقط. لتحميل متجر مفاتيح Android، مرِّر "AndroidKeyStore" إلى KeyStore.getInstance().

    لإدارة بيانات الاعتماد الخاصة لتطبيقك في متجر مفاتيح Android، عليك إنشاء مفتاح جديد باستخدام KeyPairGenerator مع KeyPairGeneratorSpec. أولاً، احصل على مثيل KeyPairGenerator من خلال استدعاء getInstance(). استدعِ بعدها initialize()، وامنحه مثيلاً من KeyPairGeneratorSpec يمكنك الحصول عليه باستخدام KeyPairGeneratorSpec.Builder. أخيرًا، يمكنك الحصول على KeyPair من خلال الاتصال على generateKeyPair().

    تخزين بيانات اعتماد الأجهزة

    يتيح Android الآن أيضًا استخدام ميزة التخزين المستنِدة إلى الأجهزة لبيانات اعتماد KeyChain، ما يوفّر المزيد من الأمان من خلال عدم إتاحة إمكانية استخراج المفاتيح. وهذا يعني أنّه بمجرد أن تكون المفاتيح في مخزن مفاتيح مستندة إلى الأجهزة (عنصر آمن أو وحدة النظام الأساسي الموثوق TPM أو TrustZone)، يمكن استخدامها في عمليات التشفير ولكن لا يمكن تصدير مواد المفاتيح الخاصة. حتى نواة نظام التشغيل لا يمكنها الوصول إلى هذه المواد الأساسية. على الرغم من أنّ بعض الأجهزة التي تعمل بنظام التشغيل Android لا تتيح إمكانية التخزين على الأجهزة، يمكنك التحقّق في وقت التشغيل ممّا إذا كانت مساحة التخزين المستنِدة إلى الأجهزة متاحة من خلال الاتصال بـ KeyChain.IsBoundKeyAlgorithm().

    نماذج البيان

    الميزات المطلوبة التي يمكن تعريفها

    أصبحت القيم التالية متوافقة الآن في العنصر <uses-feature>، حتى تتمكّن من التأكد من أنّ تطبيقك لا يتم تثبيته إلا على الأجهزة التي توفّر الميزات التي يحتاجها تطبيقك.

    FEATURE_APP_WIDGETS
    يجب أن تتم الإشارة إلى أنّ تطبيقك يوفّر تطبيق مصغّر، ويجب تثبيته فقط على الأجهزة التي تتضمّن شاشة رئيسية أو موقعًا مشابهًا حيث يمكن للمستخدمين تضمين التطبيقات المصغّرة. مثال:
    <uses-feature android:name="android.software.app_widgets" android:required="true" />
    
    FEATURE_HOME_SCREEN
    يوضح أنّ تطبيقك يعمل كبديل للشاشة الرئيسية، ويجب تثبيته فقط على الأجهزة التي تتوافق مع تطبيقات الشاشة الرئيسية التابعة لجهات خارجية. مثال:
    <uses-feature android:name="android.software.home_screen" android:required="true" />
    
    FEATURE_INPUT_METHODS
    يجب الإقرار بأنّ تطبيقك يوفّر أسلوب إدخال مخصّصًا (لوحة مفاتيح تم تصميمها باستخدام InputMethodService) وأنّه يجب تثبيته فقط على الأجهزة التي تتوافق مع أساليب الإدخال التابعة لجهات خارجية. مثال:
    <uses-feature android:name="android.software.input_methods" android:required="true" />
    
    FEATURE_BLUETOOTH_LE
    يوضح أنّ تطبيقك يستخدم واجهات برمجة تطبيقات Bluetooth Low Energy API، ويجب تثبيته فقط على الأجهزة القادرة على الاتصال بالأجهزة الأخرى عبر Bluetooth Low Energy. مثال:
    <uses-feature android:name="android.software.bluetooth_le" android:required="true" />
    

    أذونات المستخدمين

    القيم التالية متوافقة الآن في <uses-permission> لتعريف الأذونات التي يتطلبها تطبيقك للوصول إلى واجهات برمجة تطبيقات معيّنة.

    BIND_NOTIFICATION_LISTENER_SERVICE
    مطلوب لاستخدام واجهات برمجة التطبيقات NotificationListenerService الجديدة.
    SEND_RESPOND_VIA_MESSAGE
    مطلوب لتلقّي هدف ACTION_RESPOND_VIA_MESSAGE.

    للحصول على عرض تفصيلي لجميع التغييرات في واجهة برمجة التطبيقات في Android 4.3، يمكنك الاطّلاع على تقرير اختلافات واجهة برمجة التطبيقات.