نظرة عامة على أجهزة الاستشعار

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

تتيح منصة Android ثلاث فئات عامة من أجهزة الاستشعار:

  • أجهزة استشعار الحركة

    تقيس هذه الحساسات قوى التسارع وقوى الدوران على طول ثلاثة محاور. وتشمل هذه الفئة مقاييس التسارع وأجهزة استشعار الجاذبية وأجهزة الجيروسكوب وأجهزة استشعار المتّجهات الدورانية.

  • أجهزة الاستشعار البيئية

    تقيس هذه الحساسات المَعلمات البيئية المختلفة، مثل درجة حرارة الهواء المحيط والضغط والإضاءة والرطوبة. تشمل هذه الفئة مقاييس الضغط الجوي وأجهزة قياس الإضاءة ومقاييس حرارة الغرفة.

  • أجهزة استشعار الموضع

    تقيس هذه الأدوات الموقع الجغرافي للجهاز. وتشمل هذه الفئة أجهزة استشعار الاتجاه ومقاييس المغناطيسية.

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

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

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

مقدمة عن أجهزة الاستشعار

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

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

الجدول 1: أنواع الحساسات المتوافقة مع نظام Android الأساسي

أداة استشعار النوع الوصف الاستخدامات الشائعة
TYPE_ACCELEROMETER الأجهزة يقيس هذا المقياس قوة التسارع بوحدة متر في الثانية2 التي يتم تطبيقها على جهاز على جميع المحاور الثلاثة (x وy وz)، بما في ذلك قوة الجاذبية. رصد الحركة (الاهتزاز أو الميل أو غير ذلك)
TYPE_AMBIENT_TEMPERATURE الأجهزة يقيس درجة الحرارة المحيطة في الغرفة بالدرجة المئوية (°C). يُرجى الاطّلاع على الملاحظة أدناه. مراقبة درجات حرارة الهواء
TYPE_GRAVITY البرامج أو الأجهزة تقيس قوة الجاذبية بوحدة m/s2 التي يتم تطبيقها على جهاز على كل المحاور الثلاثة (x وy وz). رصد الحركة (الاهتزاز أو الميل أو غير ذلك)
TYPE_GYROSCOPE الأجهزة تقيس هذه السمة معدّل دوران الجهاز بالراديان في الثانية حول كلّ من السواطير الثلاثة (x وy وz). رصد التدوير (الدوران أو الالتفاف أو غير ذلك)
TYPE_LIGHT الأجهزة تقيس هذه الميزة مستوى الإضاءة المحيطة (الإضاءة) بالوحدة lx. التحكّم في سطوع الشاشة
TYPE_LINEAR_ACCELERATION البرامج أو الأجهزة يقيس هذا المقياس قوة التسارع بوحدة متر في الثانية2 التي يتم تطبيقها على جهاز على جميع المحاور الثلاثة (x وy وz)، باستثناء قوة الجاذبية. رصد التسارع على محور واحد.
TYPE_MAGNETIC_FIELD الأجهزة يقيس المجال المغناطيسي المحيطي لجميع المحاور المادية الثلاثة (س، ص، ع) بالميكرومتر. إنشاء بوصلة
TYPE_ORIENTATION البرامج تقيس درجات الدوران التي يجريها الجهاز حول جميع المحاور الثلاثة (x وy وz). اعتبارًا من المستوى 3 من واجهة برمجة التطبيقات، يمكنك الحصول على مصفوفة الميل ومصفوفة الدوران لجهاز باستخدام جهاز استشعار الجاذبية وجهاز استشعار الحقل المغناطيسي الأرضي مع استخدام getRotationMatrix() الطريقة. جارٍ تحديد موضع الجهاز.
TYPE_PRESSURE الأجهزة تقيس هذه القيمة ضغط الهواء المحيط بالوحدة hPa أو mbar. مراقبة التغيُّرات في ضغط الهواء
TYPE_PROXIMITY الأجهزة تقيس هذه السمة مدى قرب جسم معيّن بالسنتيمترات من شاشة العرض في الجهاز. يُستخدَم هذا المستشعر عادةً لتحديد ما إذا كان الهاتف الجوّال مُمسكًا به عند أذن المستخدم. موضع الهاتف أثناء المكالمة
TYPE_RELATIVE_HUMIDITY الأجهزة يقيس الرطوبة النسبية للبيئة المحيطة بالمقياس المئوي (%). مراقبة نقطة الندى والرطوبة المطلقة والرطوبة النسبية
TYPE_ROTATION_VECTOR البرامج أو الأجهزة تقيس اتجاه الجهاز من خلال توفير العناصر الثلاثة لمتجه دوران الجهاز. رصد الحركة ورصد الالتفاف
TYPE_TEMPERATURE الأجهزة يقيس درجة حرارة الجهاز بالدرجة المئوية. يختلف تنفيذ هذا المستشعر باختلاف الأجهزة، وقد تم استبداله بمستشعر TYPE_AMBIENT_TEMPERATURE في المستوى 14 لواجهة برمجة التطبيقات. جارٍ مراقبة درجات الحرارة.

إطار عمل الاستشعار

يمكنك الوصول إلى أدوات الاستشعار هذه والحصول على بياناتها الأولية بالمستشعر باستخدام إطار عمل أداة استشعار Android. تشكّل إطار عمل الاستشعار جزءًا من حزمة android.hardware وتتضمّن الklassen والواجهات التالية:

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

في التطبيق العادي، يتم استخدام واجهات برمجة التطبيقات هذه ذات الصلة بأجهزة الاستشعار لتنفيذ مهمتَين أساسيتَين:

  • تحديد أدوات الاستشعار وإمكاناتها

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

  • مراقبة أحداث أجهزة الاستشعار

    تتيح لك مراقبة أحداث أجهزة الاستشعار الحصول على بيانات أجهزة الاستشعار الأوّلية. ويحدث جهاز الاستشعار في كل مرة يرصد فيها جهاز الاستشعار تغييرًا في المَعلمات التي يقيسها. يوفّر لك حدث الاستشعار أربع معلومات: اسم أداة الاستشعار التي تسبّبت في الحدث، والطابع الزمني للحدث، ودقّة الحدث، وبيانات أداة الاستشعار الأوّلية التي تسبّبت في الحدث.

مدى توفّر أداة الاستشعار

يختلف مدى توفّر أداة الاستشعار من جهاز إلى آخر، وقد يختلف أيضًا بين إصدارات Android. ويرجع ذلك إلى أنّ أدوات استشعار Android قد تم طرحها على مدار عدة إصدارات من النظام الأساسي. على سبيل المثال، تم تقديم العديد من أدوات الاستشعار في Android 1.5 (المستوى 3 لواجهة برمجة التطبيقات)، ولكن لم يتم تنفيذ بعضها ولم يكن متاحًا للاستخدام حتى الإصدار Android 2.3 (مستوى واجهة برمجة التطبيقات 9). وبالمثل، تم طرح العديد من أجهزة الاستشعار في الإصدار 2.3 من نظام التشغيل Android (المستوى 9 لواجهة برمجة التطبيقات) والإصدار 4.0 من نظام التشغيل Android (المستوى 14 لواجهة برمجة التطبيقات). تم إيقاف جهازَي قياس درجة الحرارة نهائيًا واستبدالهما بأجهزة قياس أحدث وأفضل.

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

الجدول 2: مدى توفّر أجهزة الاستشعار حسب المنصة

أداة استشعار الإصدار 4.0 من نظام التشغيل Android
(المستوى 14 لواجهة برمجة التطبيقات)
الإصدار 2.3 من نظام التشغيل Android
(المستوى 9 من واجهة برمجة التطبيقات)
الإصدار 2.2 من نظام التشغيل Android
(المستوى 8 لواجهة برمجة التطبيقات)
الإصدار 1.5 من نظام التشغيل Android
(المستوى 3 لواجهة برمجة التطبيقات)
TYPE_ACCELEROMETER نعم نعم نعم نعم
TYPE_AMBIENT_TEMPERATURE نعم لا تنطبق لا تنطبق لا تنطبق
TYPE_GRAVITY نعم نعم لا تنطبق لا تنطبق
TYPE_GYROSCOPE نعم نعم لا تنطبق1 لا تنطبق1
TYPE_LIGHT نعم نعم نعم نعم
TYPE_LINEAR_ACCELERATION نعم نعم لا تنطبق لا تنطبق
TYPE_MAGNETIC_FIELD نعم نعم نعم نعم
TYPE_ORIENTATION نعم2 نعم2 نعم2 نعم
TYPE_PRESSURE نعم نعم لا تنطبق1 لا تنطبق1
TYPE_PROXIMITY نعم نعم نعم نعم
TYPE_RELATIVE_HUMIDITY نعم لا تنطبق لا تنطبق لا تنطبق
TYPE_ROTATION_VECTOR نعم نعم لا تنطبق لا تنطبق
TYPE_TEMPERATURE نعم2 نعم نعم نعم

1 تمت إضافة نوع أداة الاستشعار هذا في Android 1.5 (المستوى 3 لواجهة برمجة التطبيقات)، ولكنه لم يكن متاحًا للاستخدام حتى Android 2.3 (المستوى 9 لواجهة برمجة التطبيقات).

2 أداة الاستشعار هذه متاحة، ولكن تم إيقافها نهائيًا.

تحديد أدوات الاستشعار وإمكاناتها

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

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

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

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

Kotlin

val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)

Java

List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);

إذا كنت تريد إدراج جميع أجهزة الاستشعار من نوع معيّن، يمكنك استخدام ثابت آخر بدلاً من TYPE_ALL مثل TYPE_GYROSCOPE أو TYPE_LINEAR_ACCELERATION أو TYPE_GRAVITY.

يمكنك أيضًا تحديد ما إذا كان هناك نوع معيّن من أدوات الاستشعار على جهاز معيّن باستخدام الطريقة getDefaultSensor() وإدخال الثابت type لجهاز استشعار معيّن. إذا كان الجهاز يحتوي على أكثر من أداة استشعار واحدة من نوع معيّن، يجب تحديد إحدى الأدوات على أنّها أداة الاستشعار التلقائية. إذا لم يكن هناك جهاز استشعار تلقائي لنوع معيّن من أجهزة الاستشعار، ستُعرِض طريقة الطلب قيمة فارغة، ما يعني أنّ الجهاز لا يحتوي على هذا النوع من أجهزة الاستشعار. على سبيل المثال، تتحقّق التعليمة البرمجية التالية ممّا إذا كان هناك مقياس مغناطيسي على الجهاز:

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

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

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

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

Kotlin

private lateinit var sensorManager: SensorManager
private var mSensor: Sensor? = null

...

sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
    val gravSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY)
    // Use the version 3 gravity sensor.
    mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 }
}
if (mSensor == null) {
    // Use the accelerometer.
    mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    } else {
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
        null
    }
}

Java

private SensorManager sensorManager;
private Sensor mSensor;

...

sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = null;

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
    List<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY);
    for(int i=0; i<gravSensors.size(); i++) {
        if ((gravSensors.get(i).getVendor().contains("Google LLC")) &&
           (gravSensors.get(i).getVersion() == 3)){
            // Use the version 3 gravity sensor.
            mSensor = gravSensors.get(i);
        }
    }
}
if (mSensor == null){
    // Use the accelerometer.
    if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
        mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    } else{
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
    }
}

وهناك طريقة أخرى مفيدة وهي getMinDelay() التي تعرض الحد الأدنى من الفاصل الزمني (بالميكرو ثانية) التي يمكن لأداة الاستشعار استخدامها لاستشعار البيانات. أي جهاز استشعار يعرض قيمة غير صفرية لطريقة getMinDelay() هو جهاز استشعار بث. ترصد أجهزة استشعار البث البيانات على فترات منتظمة، وقد تم طرحها في Android 2.3 (المستوى 9 من واجهة برمجة التطبيقات). إذا كان جهاز الاستشعار يعرض القيمة صفر عند استدعاء الطريقة getMinDelay()، يعني ذلك أنّه ليس جهاز استشعار بثّ لأنّه لا يُبلغ عن البيانات إلا عند حدوث تغيير في المَعلمات التي يرصدها.

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

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

مراقبة أحداث أجهزة الاستشعار

لمراقبة بيانات الاستشعار الأوّلية، عليك تنفيذ طريقتَي استدعاء يتم عرضهما من خلال واجهة SensorEventListener: onAccuracyChanged() وonSensorChanged(). يطلب نظام Android هذه الطرق كلما حدث ما يلي:

  • تغيُّر دقة أحد أجهزة الاستشعار

    في هذه الحالة، يستدعي النظام الطريقة onAccuracyChanged()، ما يوفّر لك إشارة إلى الكائن Sensor الذي تم تغييره والدقة الجديدة لأداة الاستشعار. يتم تمثيل الدقة بأحد الثوابت الأربعة للحالة: SENSOR_STATUS_ACCURACY_LOW، SENSOR_STATUS_ACCURACY_MEDIUM، SENSOR_STATUS_ACCURACY_HIGH، أو SENSOR_STATUS_UNRELIABLE.

  • يُبلِغ أحد أجهزة الاستشعار عن قيمة جديدة.

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

يوضّح الرمز التالي كيفية استخدام طريقة onSensorChanged() لمراقبة البيانات الواردة من جهاز استشعار الضوء. يعرض هذا المثال بيانات أداة الاستشعار الأوّلية في TextView يتم تعريفها في ملف main.xml على أنّها sensor_data.

Kotlin

class SensorActivity : Activity(), SensorEventListener {
    private lateinit var sensorManager: SensorManager
    private var mLight: Sensor? = null

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)

        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
    }

    override fun onSensorChanged(event: SensorEvent) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        val lux = event.values[0]
        // Do something with this sensor value.
    }

    override fun onResume() {
        super.onResume()
        mLight?.also { light ->
            sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

Java

public class SensorActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor mLight;

    @Override
    public final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
    }

    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
    }

    @Override
    public final void onSensorChanged(SensorEvent event) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        float lux = event.values[0];
        // Do something with this sensor value.
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

في هذا المثال، يتم تحديد تأخُّر البيانات التلقائي (SENSOR_DELAY_NORMAL) عند استدعاء الطريقة registerListener(). يتحكّم تأخُّر تسجيل البيانات (أو معدّل أخذ العينات) في الفاصل الزمني الذي يتم فيه إرسال أحداث أداة الاستشعار إلى تطبيقك من خلال طريقة الاستدعاء onSensorChanged(). يتناسب تأخير البيانات الافتراضي مع مراقبة التغييرات النموذجية في اتجاه الشاشة ويستخدم تأخيرًا قدره 200000 ميكرو ثانية. يمكنك تحديد تأخّرات data أخرى، مثل SENSOR_DELAY_GAME (تأخّر 20,000 ملي ثانية)، أو SENSOR_DELAY_UI (تأخّر 60,000 ملي ثانية)، أو SENSOR_DELAY_FASTEST (تأخّر 0 ملي ثانية). اعتبارًا من الإصدار 3.0 من Android (المستوى 11 من واجهة برمجة التطبيقات)، يمكنك أيضًا تحديد المدة الزمنية كمقدار مطلق (بالميكرو ثانية).

إنّ المهلة التي تحدّدها هي مهلة مقترَحة فقط. يمكن لنظام Android والتطبيقات الأخرى تغيير هذا التأخير. من بين أفضل الممارسات، يجب تحديد أكبر وقت ممكن لأن النظام يستخدم عادةً تأخيرًا أقل من ذلك الذي تحدّده (أي يجب اختيار أبطأ معدّل لأخذ العينات لا يزال يفي باحتياجات تطبيقك). يؤدي استخدام تأخير أكبر إلى خفض عبء العمل على المعالج وبالتالي استخدام طاقة أقل.

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

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

التعامل مع إعدادات أجهزة الاستشعار المختلفة

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

لديك خياران للتأكّد من توفّر أداة استشعار معيّنة على الجهاز:

  • رصد أجهزة الاستشعار أثناء التشغيل وتفعيل ميزات التطبيق أو إيقافها حسب الاقتضاء
  • استخدِم فلاتر Google Play لاستهداف الأجهزة التي تتضمّن إعدادات محدّدة لأجهزة الاستشعار.

يتمّ مناقشة كلّ خيار في الأقسام التالية.

رصد أدوات الاستشعار في وقت التشغيل

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

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) {
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

استخدام فلاتر Google Play لاستهداف إعدادات أداة استشعار معيّنة

إذا كنت بصدد نشر تطبيقك على Google Play، يمكنك استخدام العنصر <uses-feature> في ملف البيان لفلترة تطبيقك من الأجهزة التي لا تملك إعدادات أداة الاستشعار المناسبة لتطبيقك. ويتضمّن العنصر <uses-feature> العديد من أدوات الوصف للأجهزة التي تتيح لك فلترة التطبيقات استنادًا إلى توفُّر أدوات استشعار محدّدة. تشمل أدوات الاستشعار التي يمكنك إدراجها ما يلي: مقياس التسارع ومقياس الضغط الجوي والبوصلة (المجال المغناطيسي الأرضي) والجيروسكوب والضوء والقرب. في ما يلي مثال على إدخال ملف البيان الذي لفلترة التطبيقات التي لا تحتوي على مقياس تسارع:

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

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

ويجب عدم ضبط الواصف على android:required="true" إلا إذا كان تطبيقك يعتمد بالكامل على أداة استشعار محددة. إذا كان تطبيقك يستخدم أداة استشعار لأداء بعض الوظائف، ولكنه لا يزال يعمل بدون أداة الاستشعار، يجب إدراج أداة الاستشعار في العنصر <uses-feature>، مع ضبط أداة الوصف على android:required="false". يساعد ذلك في ضمان أنّه يمكن للأجهزة تثبيت تطبيقك حتى إذا لم تكن مزوّدة بجهاز الاستشعار المحدّد. وهذه أيضًا من أفضل ممارسات إدارة المشروعات التي تساعدك على تتبع الميزات التي يستخدمها تطبيقك. يُرجى العِلم أنّه إذا كان تطبيقك يستخدم أداة استشعار معيّنة، ولكنه لا يزال يعمل بدونها، عليك رصد أداة الاستشعار أثناء التشغيل وإيقاف ميزات التطبيق أو تفعيلها حسب الحاجة.

نظام إحداثيات أداة الاستشعار

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

الشكل 1: نظام الإحداثيات (بالنسبة إلى جهاز) الذي تستخدمه واجهة برمجة تطبيقات أدوات الاستخدام.

وأهم نقطة يجب فهمها بشأن نظام الإحداثيات هذا هي أنّ المحاور لا يتم تبديلها عند تغيير اتجاه شاشة الجهاز، أي أنّ نظام الإحداثيات في أداة الاستشعار لا يتغيّر أبدًا مع تحرك الجهاز. وهذا السلوك هو نفسه سلوك نظام إحداثيات OpenGL.

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

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

ملاحظة: تستخدِم بعض الحساسات والأساليب نظام إحداثيات نسبيًا إلى إطار مرجعي عالمي (على عكس إطار مرجعي الجهاز). وتعرض هذه المستشعرات والأساليب بيانات تمثل حركة الجهاز أو موضعه بالنسبة إلى الأرض. لمزيد من المعلومات، اطّلِع على طريقة getOrientation() وطريقة getRotationMatrix() وOrientation Sensor وRotation Vector Sensor.

الحدّ من معدّل نقل أجهزة الاستشعار

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

يعتمد الحدّ الأقصى لمعدّل التحديث على طريقة وصولك إلى بيانات جهاز الاستشعار:

  • في حال استدعاء الأسلوب registerListener() لمراقبة أحداث أجهزة الاستشعار، يكون معدّل أخذ العينات من أجهزة الاستشعار محدودًا بـ 200 هرتز. وينطبق ذلك على جميع الصيغ المُحمَّلة من الأسلوب registerListener().
  • في حال استخدام فئة SensorDirectChannel، يقتصر معدّل أخذ العينات من المستشعر على RATE_NORMAL، وهو عادةً ما يقارب 50 هرتز.

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

AndroidManifest.xml

<manifest ...>
    <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
    <application ...>
        ...
    </application>
</manifest>

أفضل الممارسات للوصول إلى أجهزة الاستشعار واستخدامها

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

جمع بيانات أجهزة الاستشعار في المقدّمة فقط

على الأجهزة التي تعمل بالإصدار 9 من نظام التشغيل Android (المستوى 28 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، تخضع التطبيقات التي تعمل في الخلفية للقيود التالية:

  • لا تتلقّى أجهزة الاستشعار المستمرة لوضع التقارير، مثل مقاييس التسارع والجيروسكوب.
  • لا تتلقّى أجهزة الاستشعار التي تستخدم وضع إعداد التقارير عند التغيير أو اللقطة الواحدة أحداثًا.

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

إلغاء تسجيل أدوات الاستماع إلى أجهزة الاستشعار

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

Kotlin

private lateinit var sensorManager: SensorManager
...
override fun onPause() {
    super.onPause()
    sensorManager.unregisterListener(this)
}

Java

private SensorManager sensorManager;
...
@Override
protected void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
}

لمزيد من المعلومات، يُرجى الاطّلاع على "unregisterListener(SensorEventListener)".

الاختبار باستخدام "محاكي Android"

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

يستخدم المحاكي اتصالاً بجهاز Android يعمل بتطبيق SdkControllerSensor. يُرجى العِلم أنّ هذا التطبيق لا يتوفّر إلا على الأجهزة التي تعمل بالإصدار 4.0 من نظام التشغيل Android (المستوى 14 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث. (إذا كان الجهاز يعمل بنظام التشغيل Android 4.0، يجب أن يكون عليه الإصدار 2 مثبَّتًا). يراقب تطبيق SdkControllerSensor التغييرات في أجهزة الاستشعار على الجهاز وينقلها إلى المحاكي. تتم بعد ذلك معالجة المحاكي استنادًا إلى القيم الجديدة التي يتلقّاها من أجهزة الاستشعار في جهازك.

يمكنك الاطّلاع على رمز المصدر لتطبيق SdkControllerSensor في الموقع التالي:

$ your-android-sdk-directory/tools/apps/SdkController

لنقل البيانات بين جهازك والمحاكي، اتّبِع الخطوات التالية:

  1. تأكَّد من تفعيل تصحيح أخطاء USB على جهازك.
  2. وصِّل جهازك بجهاز التطوير باستخدام كابل USB.
  3. ابدأ تطبيق SdkControllerSensor على جهازك.
  4. في التطبيق، اختَر أجهزة الاستشعار التي تريد محاكاتها.
  5. شغِّل أمر adb التالي:

  6. $ adb forward tcp:1968 tcp:1968
    
  7. ابدأ تشغيل المحاكي. من المفترض أن تتمكّن الآن من تطبيق عمليات التحويل على الemualtor عن طريق تحريك جهازك.

ملاحظة: إذا لم تؤدِ الحركات التي تجريها على الجهاز الفعلي إلى تحويل المحاكي، حاوِل تشغيل الأمر adb من الخطوة 5 مرة أخرى.

لمزيد من المعلومات، يمكنك الاطّلاع على دليل محاكي Android.

لا تحظر الطريقة onSensorChanged()‎.

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

تجنُّب استخدام طرق تم إيقافها نهائيًا أو أنواع أدوات الاستشعار

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

التحقّق من صحة بيانات أجهزة الاستشعار قبل استخدامها

تأكَّد دائمًا من توفُّر أداة استشعار على الجهاز قبل محاولة الحصول على بيانات منه. لاتفترض أنّ هناك جهاز استشعار متوفّرًا لمجرد أنّه جهاز استشعار يتم استخدامه بشكل متكرر. ليس على الشركات المصنّعة للأجهزة توفير أي أدوات استشعار معيّنة في أجهزتها.

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

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