חיישני מיקום

בפלטפורמת Android יש שני חיישנים שמאפשרים לקבוע את המיקום של המכשיר: חיישן השדה הגאומגנטי ומד התאוצה. מכשיר Android מספקת גם חיישן שמאפשר לך לקבוע את מידת המרחק בין הפנים מכשיר צמוד לאובייקט (שנקרא חיישן קירבה). חיישן שדה גיאומגנטי וחיישן הקירבה מבוססים על חומרה. נפוצים יצרני טלפונים וטאבלטים כוללים חיישן שדה גיאומגנטי. באופן דומה, יצרני טלפונים ניידים משתמשים בדרך כלל בחיישן קירבה כדי לקבוע מתי הטלפון מוחזק קרוב לפנים של המשתמש (לדוגמה, במהלך שיחת טלפון שיחה). כדי לקבוע את כיוון המכשיר, אפשר להשתמש בקריאות מהטבלה את מד התאוצה של המכשיר ואת חיישן השדה הגאומגנטי.

הערה: חיישן הכיוון הוצא משימוש ב-Android 2.2 (API ברמה 8), וסוג חיישן הכיוון הוצא משימוש ב-Android 4.4W (רמת API 20).

חיישני המיקום שימושיים לקביעת המיקום הפיזי של המכשיר את מודל השיוך של העולם. לדוגמה, אפשר להשתמש בשדה הגאומגנטי החיישן בשילוב עם מד התאוצה כדי לקבוע את מיקום המכשיר ביחס לקוטב הצפוני המגנטי. אפשר להשתמש בחיישנים האלה גם כדי לקבוע את כיוון המכשיר במסגרת ההפניה של האפליקציה. חיישני מיקום לא משמשים בדרך כלל כדי לעקוב אחר תנועה או תנועה של המכשיר, כמו ניעור, הטיה או דחף (מידע נוסף זמין במאמר חיישני תנועה).

חיישן השדה הגאומגנטי ומד התאוצה מחזירים מערכים רב-ממדיים מערכי החיישנים של כל SensorEvent. לדוגמה, שחיישן השדה הגאומגנטי מספק ערכים של חוזק שדה גיאומגנטי כל אחד משלושת צירי הקואורדינטות במהלך אירוע יחיד של חיישן. באופן דומה, החיישן של מד התאוצה מודד את התאוצה שמופעלת על המכשיר במהלך אירוע מחיישן. למידע נוסף על מערכות הקואורדינטות המשמשות על ידי חיישנים, לראות מערכות קואורדינטות של חיישנים חיישן הקירבה מספק ערך יחיד לכל אירוע חיישן. טבלה 1 מסכמת את חיישני המיקום נתמך בפלטפורמת Android.

טבלה 1. חיישני מיקום הנתמכים בפלטפורמת Android.

חיישן נתוני אירועים מחיישנים תיאור יחידות מידה
TYPE_GAME_ROTATION_VECTOR SensorEvent.values[0] רכיב וקטור סיבוב לאורך ציר ה-x (x * sin(סיכום/2)). ללא יחידה
SensorEvent.values[1] רכיב וקטור סיבוב לאורך ציר ה-y (y * sin(סיכום/2)).
SensorEvent.values[2] רכיב וקטור סיבוב לאורך ציר ה-z (z * sin(ישתמשו במחשב 2)).
TYPE_GEOMAGNETIC_ROTATION_VECTOR SensorEvent.values[0] רכיב וקטור סיבוב לאורך ציר ה-x (x * sin(סיכום/2)). ללא יחידה
SensorEvent.values[1] רכיב וקטור סיבוב לאורך ציר ה-y (y * sin(סיכום/2)).
SensorEvent.values[2] רכיב וקטור סיבוב לאורך ציר ה-z (z * sin(ישתמשו במחשב 2)).
TYPE_MAGNETIC_FIELD SensorEvent.values[0] עוצמת שדה גיאומגנטי לאורך ציר ה-X. μT
SensorEvent.values[1] עוצמת שדה גיאומגנטי לאורך ציר ה-Y.
SensorEvent.values[2] עוצמת שדה גיאומגנטי לאורך ציר ה-z.
TYPE_MAGNETIC_FIELD_UNCALIBRATED SensorEvent.values[0] עוצמת שדה גיאומגנטי (ללא כיול ברזל קשיח) לאורך ציר ה-X. μT
SensorEvent.values[1] עוצמת שדה גיאומגנטי (ללא כיול ברזל קשיח) לאורך ציר ה-Y.
SensorEvent.values[2] עוצמת שדה גיאומגנטי (ללא כיול ברזל קשיח) לאורך ציר ה-z.
SensorEvent.values[3] הערכה של הטיות הברזל לאורך ציר ה-X.
SensorEvent.values[4] הערכה של הטיה בברזל לאורך ציר ה-y.
SensorEvent.values[5] הערכה של הטיות הברזל לאורך ציר ה-z.
TYPE_ORIENTATION1 SensorEvent.values[0] אזימוט (זווית סביב ציר ה-z). מעלות
SensorEvent.values[1] גודל גובה-רוחב (זווית סביב ציר ה-X).
SensorEvent.values[2] גלילה (זווית סביב ציר ה-Y).
TYPE_PROXIMITY SensorEvent.values[0] מרחק מהעצם.2 ס"מ

1החיישן הזה הוצא משימוש ב-Android 2.2 (API רמה 8), וסוג החיישן הזה הוצא משימוש ב-Android 4.4W (רמת API 20). מסגרת החיישן מספקת שיטות חלופיות לצירוף המכשיר לכיוון אוטומטי, שנדון ב בכיוון של המכשיר.

2 חלק מחיישני הקירבה מספקים רק ערכים בינאריים שמייצגים קרובים ורחוק.

שימוש בחיישן הווקטור של סיבוב המשחק

חיישן הווקטור של הסיבוב של המשחק זהה לחיישן רוטציה וחיישן וקטורי, אבל הוא לא משתמש בשדה הגאומגנטי. לכן ציר ה-Y לא לכיוון צפון, אלא במקום זאת להתייחסות אחרת. להפניה הזו מותר להיסחף באמצעות אותו סדר גודל כמו הג'ירוסקופ נע סביב ציר ה-Z.

מכיוון שחיישן הווקטור של סיבוב המשחק לא משתמש בשדה המגנטי, הסיבובים היחסיים לא משתמשים מדויקים יותר, ולא מושפעים משינויים בשדה המגנטי. כדאי להשתמש בחיישן הזה במשחק אם לא משנה לך איפה הצפון נמצא והווקטור הנורמלי של הסיבוב לא מתאים לצרכים שלך בגלל ההסתמכות שלו על השדה המגנטי.

הקוד הבא מראה איך לאחזר מופע של וקטור ברירת המחדל של סבב משחקים חיישן:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);

שימוש בחיישן וקטור הסיבוב הגאומגנטי

החיישן הגאומגנטי של וקטור הסיבוב דומה וחיישן וקטורי סיבוב, לא נעשה בו שימוש בג'ירוסקופ. רמת הדיוק של החיישן הזה נמוכה מהווקטור הסיבוב הרגיל אבל צריכת החשמל נמוכה יותר. צריך להשתמש בחיישן הזה רק אם רוצים לאסוף סיבוב נתונים מידע ברקע בלי לצרוך יותר מדי סוללה. החיישן הזה מאוד שימושי כשמשתמשים בו בשילוב עם קיבוץ באצווה של קריאות.

הקוד הבא מראה איך לקבל מופע של הסיבוב הגאומגנטי שמוגדר כברירת מחדל חיישן וקטורי:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);

מחשבים את כיוון המכשיר

חישוב כיוון המכשיר מאפשר לך לעקוב אחר המיקום של ביחס למסגרת הייחוס של כדור הארץ (ספציפית, המודל המגנטי הקוטב הצפוני). הקוד הבא מראה איך לחשב כיוון:

Kotlin

private lateinit var sensorManager: SensorManager
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
val rotationMatrix = FloatArray(9)
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading)

// Express the updated rotation matrix as three orientation angles.
val orientationAngles = FloatArray(3)
SensorManager.getOrientation(rotationMatrix, orientationAngles)

Java

private SensorManager sensorManager;
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
final float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null,
    accelerometerReading, magnetometerReading);

// Express the updated rotation matrix as three orientation angles.
final float[] orientationAngles = new float[3];
SensorManager.getOrientation(rotationMatrix, orientationAngles);

המערכת מחשבת את זוויות הכיוון באמצעות התנועה הגאומגנטית של המכשיר חיישן שדה בשילוב עם מד התאוצה של המכשיר. באמצעות שני התרחישים האלה חיישני חומרה, המערכת מספקת נתונים עבור שלושת הסוגים הבאים זוויות הכיוון של המכשיר:

  • אזימוט (מעלות סיבוב סביב ציר z-). הדבר הזווית שבין כיוון המצפן הנוכחי של המכשיר לצפון מגנטי. אם הקצה העליון של המכשיר פונה לכיוון צפון מגנטי, האזימוט הוא 0 מעלות; אם הקצה העליון פונה דרומה, האזימוט הוא 180 מעלות. באופן דומה, אם הקצה העליון פונה מזרחה, האזימוט הוא 90 מעלות, ואם הקצה העליון שפונה מערבה, האזימוט הוא 270 מעלות.
  • רוחב (מעלות הסיבוב סביב ציר ה-X) כאן בין מישור מקביל למסך המכשיר לבין מישור מקביל לקרקע. אם מחזיקים את המכשיר במקביל לקרקע עם החלק התחתון הקצה הקרוב אליך ביותר ולהטות את הקצה העליון של המכשיר לכיוון הקרקע, הזווית של גובה הצליל הופכת לחיובית. הטיה לכיוון הנגדי – הזזת הקצה העליון של המכשיר מהקרקע — גורם את זווית הגובה-רוחב לשלילית. טווח הערכים הוא -90 מעלות עד 90 מעלות.
  • גליל (מעלות הסיבוב סביב ציר ה-Y) כאן הזווית בין מישור מאונך למסך המכשיר לבין מישור מאונך לקרקע. אם מחזיקים את המכשיר במקביל לקרקע כשהקצה התחתון קרוב אליך ביותר, והקצה השמאלי של המכשיר לכיוון הקרקע, זווית הגלגול הופכת לחיובית. הטיה לכיוון ההפוך כיוון - הזזת הקצה הימני של המכשיר לכיוון הקרקע — שגורמת לזווית הגלגול להפוך לשלילית. טווח הערכים הוא -180 מעלות ל-180 מעלות.

הערה: הגדרת הגליל של החיישן השתנתה כדי לשקף את הרוב המכריע של יישומים בסביבה העסקית של החיישן הגיאוגרפי (geosensor).

שימו לב שזוויות אלה פועלות ממערכת קואורדינטות שונה מזו אחד שמשמש לתעופה (לפיתון, לגובה ולגלגול). במערכת התעופה, ציר ה-x נמצא לאורך הצד הארוך של המישור, מהזנב עד האף.

חיישן הכיוון מפיק את הנתונים שלו על ידי עיבוד הנתונים הגולמיים של החיישן ממד התאוצה ומחיישן השדה הגאומגנטי. בגלל העומס הכבד את העיבוד המדובר, את הדיוק והדיוק של הכיוון החיישן מצטמצם. באופן ספציפי, החיישן הזה אמין רק הזווית היא 0. לכן, חיישן הכיוון הוצא משימוש ב-Android 2.2 (רמת API 8), וסוג חיישן הכיוון הוצא משימוש ב-Android 4.4 ואט (רמת API 20). במקום להשתמש בנתונים גולמיים מחיישן הכיוון, מומלץ להשתמש בgetRotationMatrix() עם התכונה אמצעי תשלום אחד (getOrientation()) כדי לחשב את ערכי הכיוון, כפי שמוצג בדוגמת הקוד הבאה. כחלק בתהליך הזה, אפשר להשתמש remapCoordinateSystem() לתרגום של ערכי הכיוון למסגרת של האפליקציה הפניה.

Kotlin

class SensorActivity : Activity(), SensorEventListener {

    private lateinit var sensorManager: SensorManager
    private val accelerometerReading = FloatArray(3)
    private val magnetometerReading = FloatArray(3)

    private val rotationMatrix = FloatArray(9)
    private val orientationAngles = FloatArray(3)

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

    override fun onResume() {
        super.onResume()

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)?.also { accelerometer ->
            sensorManager.registerListener(
                    this,
                    accelerometer,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
        sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)?.also { magneticField ->
            sensorManager.registerListener(
                    this,
                    magneticField,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
    }

    override fun onPause() {
        super.onPause()

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this)
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    override fun onSensorChanged(event: SensorEvent) {
        if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
            System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.size)
        } else if (event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size)
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    fun updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(
                rotationMatrix,
                null,
                accelerometerReading,
                magnetometerReading
        )

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles)

        // "orientationAngles" now has up-to-date information.
    }
}

Java

public class SensorActivity extends Activity implements SensorEventListener {

    private SensorManager sensorManager;
    private final float[] accelerometerReading = new float[3];
    private final float[] magnetometerReading = new float[3];

    private final float[] rotationMatrix = new float[9];
    private final float[] orientationAngles = new float[3];

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

    @Override
    protected void onResume() {
        super.onResume();

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (accelerometer != null) {
            sensorManager.registerListener(this, accelerometer,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
        Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (magneticField != null) {
            sensorManager.registerListener(this, magneticField,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this);
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
          System.arraycopy(event.values, 0, accelerometerReading,
              0, accelerometerReading.length);
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading,
                0, magnetometerReading.length);
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    public void updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(rotationMatrix, null,
            accelerometerReading, magnetometerReading);

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles);

        // "orientationAngles" now has up-to-date information.
    }
}

בדרך כלל אין צורך לבצע עיבוד או סינון נתונים כלשהו זוויות הכיוון הגולמי של המכשיר, מלבד תרגום לתאם את המערכת למסגרת ההפניה של האפליקציה שלך.

שימוש בחיישן השדה הגאומגנטי

חיישן השדה הגאומגנטי מאפשר לכם לעקוב אחר שינויים בשדה המגנטי של כדור הארץ. בסרטון הבא מוסבר איך למצוא מופע של חיישן השדה הגאומגנטי שמוגדר כברירת מחדל:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

הערה: אם האפליקציה מטרגטת את Android 12 (רמת API 31) או החיישן הזה גבוה יותר rate-limited

החיישן הזה מספק נתונים גולמיים של חוזק שדה (ב-μT) לכל אחד משלושת צירי הקואורדינטות. בדרך כלל אין צורך להשתמש בחיישן הזה ישירות. במקום זאת, אפשר להשתמש בווקטור הסיבוב כדי לקבוע את התנועה הסיבובית הגולמית, או להשתמש במד התאוצה ובשדה הגאומגנטי בשילוב עם השיטה getRotationMatrix() כדי לקבל את מטריצת הסיבוב ואת מטריצת הנטייה. לאחר מכן אפשר משתמשים במטריצות האלה עם getOrientation() והשיטות getInclination() כדי לקבל אזימוט ונתוני נטייה גיאומגנטית.

הערה: במהלך בדיקת האפליקציה, אפשר לשפר את הביצועים את הדיוק של החיישן על ידי הזזת המכשיר בצורת 8.

שימוש במגנטומטר לא מכויל

המגנטומטר הלא מכויל דומה לשדה הגאומגנטי חיישן, מלבד העובדה שלא מתבצע כיול ברזל קשיח על השדה המגנטי. כיול להגדרות המקוריות ופיצוי הטמפרטורה עדיין מוחל על השדה המגנטי. המגנטומטר הלא מכויל שימושי לטיפול בהערכות ברזל קשיחות. באופן כללי, geomagneticsensor_event.values[0] יהיה קרוב אל uncalibrated_magnetometer_event.values[0] - uncalibrated_magnetometer_event.values[3]. כלומר,

calibrated_x ~= uncalibrated_x - bias_estimate_x

הערה: חיישנים לא מכוילים מספקים תוצאות גולמיות יותר וייתכן כוללים הטיות מסוימות, אבל המדידות שלהם מכילות פחות קפיצות מתיקונים שהוחלו כיול. יכול להיות שאפליקציות מסוימות יעדיפו תוצאות לא מכוללות כך שהן חלקות יותר אמינה. למשל, אם אפליקציה מנסה לבצע היתוך חיישן משלה, כיול למעשה עלול לעוות את התוצאות.

בנוסף לשדה המגנטי, המגנטומטר הלא מכויל מספק הערכה של הטיה של ברזל קשיח בכל ציר. הקוד הבא מראה איך לקבל מופע של ברירת מחדל של מגנטומטר לא מכויל:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);

שימוש בחיישן הקירבה

חיישן הקירבה מאפשר לקבוע את המרחק של העצם מהמכשיר. הבאים שמראה איך למצוא מופע של חיישן הקירבה שמוגדר כברירת מחדל:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

חיישן הקירבה משמש בדרך כלל כדי לקבוע את המרחק של ראשו מהפנים של טלפון נייד (לדוגמה, כשמשתמש מבצע או מקבל שיחת טלפון). נפוצים חיישני קירבה מחזירים את המרחק המוחלט בס"מ, אבל חלקם חוזרים רק ליד רחוקים.

הערה: בדגמי מכשירים מסוימים חיישן הקירבה נמצא מתחת למסך, דבר שעלול לגרום להצגת נקודה מהבהבת במסך, אם האפשרות מופעלת כשהמסך מופעלת.

הקוד הבא מראה איך להשתמש בחיישן הקירבה:

Kotlin

class SensorActivity : Activity(), SensorEventListener {

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

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

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
    }

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

    override fun onSensorChanged(event: SensorEvent) {
        val distance = event.values[0]
        // Do something with this sensor data.
    }

    override fun onResume() {
        // Register a listener for the sensor.
        super.onResume()

        proximity?.also { proximity ->
            sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

Java

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

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

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    }

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

    @Override
    public final void onSensorChanged(SensorEvent event) {
        float distance = event.values[0];
        // Do something with this sensor data.
    }

    @Override
    protected void onResume() {
        // Register a listener for the sensor.
        super.onResume();
        sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL);
      }

    @Override
    protected void onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

הערה: חלק מחיישני הקירבה מחזירים ערכים בינאריים שמייצגים 'ליד' או 'far'. במקרה הזה, החיישן בדרך כלל מדווח על ערך הטווח המקסימלי שלו במצב הרחוק וערך נמוך יותר במצב הקרוב. בדרך כלל, הערך המרוחק הוא ערך > 5 ס"מ, אבל עשוי להשתנות מחיישן לחיישן. אפשר לקבוע את הטווח המקסימלי של החיישן בעזרת השיטה getMaximumRange().

כדאי גם לקרוא