Just another WordPress site

Lập trình với cảm biến xoay màn hình

Điện thoại Android thường có tích hợp cảm biến xoay màn hình (orientation sensor), dùng để phát hiện việc xoay màn hình trong không gian. Cảm biến xoay màn hình phát hiện việc xoay theo 3 giá trị:

  • Azimtuh in degres: góc giữa trục X của điện thoại và hướng bắc (0 ≤ azimuth ≤ 360)
  • Pitch in degres: góc giữa trục Y của điện thoại và đường nằm ngang (-180 ≤ pitch ≤ 180)
  • Roll in degres: góc giữa trục X của điện thoại và đường nằm ngang (-90 ≤ roll ≤ 90)

Trong bài này, tôi sẽ trình diễn cách mà cảm biến xoay màn hình trong trong chương trình bắt sự kiện. Chúng ta sẽ dùng những sự kiện này để tạo một listener xử lý khi sự kiện này xảy ra:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package net.androgames.blog.sample.orientation;
 
public interface OrientationListener {
 
    public void onOrientationChanged(float azimuth, 
            float pitch, float roll);
 
    /**
     * Top side of the phone is up
     * The phone is standing on its bottom side
     */
    public void onTopUp();
 
    /**
     * Bottom side of the phone is up
     * The phone is standing on its top side
     */
    public void onBottomUp();
 
    /**
     * Right side of the phone is up
     * The phone is standing on its left side
     */
    public void onRightUp();
 
    /**
     * Left side of the phone is up
     * The phone is standing on its right side
     */
    public void onLeftUp();
 
}

Một instance của SensorManager để nhận thông tin từ những cảm biến có trong điện thoại. Không cần yêu cầu thêm permisson gì khi truy cập tới những thông tin cảm biến của điện thoại. Để nhận danh sách những cảm biến xoay màn hình có trong điện thoại, hãy dùng giá trị Sensor.TYPE_ORIENTATION. Nếu có ít nhất 1 cảm biến, ta có thể đăng ký một SensorEventListener. Tỉ lệ trả về của cảm biến xoay có thể được chỉ định và phải là một trong số sau đây:

  • SensorManager.SENSOR_DELAY_FASTEST: nhanh nhất có thể
  • SensorManager.SENSOR_DELAY_GAME: tỉ lệ thích hợp cho game
  • SensorManager.SENSOR_DELAY_NORMAL: tỉ lệ thường dùng
  • SensorManager.SENSOR_DELAY_UI: tỉ lệ thích hợp cho UI Thread

Đây là code chỉnh sửa orientation manager:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package net.androgames.blog.sample.orientation;
 
import java.util.List;
 
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
 
/**
 * Android Orientation Sensor Manager Archetype
 * @author antoine vianey
 * under GPL v3 : http://www.gnu.org/licenses/gpl-3.0.html
 */
public class OrientationManager {
 
    private static Sensor sensor;
    private static SensorManager sensorManager;
    // you could use an OrientationListener array instead
    // if you plans to use more than one listener
    private static OrientationListener listener;
 
    /** indicates whether or not Orientation Sensor is supported */
    private static Boolean supported;
    /** indicates whether or not Orientation Sensor is running */
    private static boolean running = false;
 
    /** Sides of the phone */
    enum Side {
        TOP,
        BOTTOM,
        LEFT,
        RIGHT;
    }
 
    /**
     * Returns true if the manager is listening to orientation changes
     */
    public static boolean isListening() {
        return running;
    }
 
    /**
     * Unregisters listeners
     */
    public static void stopListening() {
        running = false;
        try {
            if (sensorManager != null && sensorEventListener != null) {
                sensorManager.unregisterListener(sensorEventListener);
            }
        } catch (Exception e) {}
    }
 
    /**
     * Returns true if at least one Orientation sensor is available
     */
    public static boolean isSupported() {
        if (supported == null) {
            if (Orientation.getContext() != null) {
                sensorManager = (SensorManager) Orientation.getContext()
                        .getSystemService(Context.SENSOR_SERVICE);
                List<Sensor> sensors = sensorManager.getSensorList(
                        Sensor.TYPE_ORIENTATION);
                supported = new Boolean(sensors.size() > 0);
            } else {
                supported = Boolean.FALSE;
            }
        }
        return supported;
    }
 
    /**
     * Registers a listener and start listening
     */
    public static void startListening(
            OrientationListener orientationListener) {
        sensorManager = (SensorManager) Orientation.getContext()
                .getSystemService(Context.SENSOR_SERVICE);
        List<Sensor> sensors = sensorManager.getSensorList(
                Sensor.TYPE_ORIENTATION);
        if (sensors.size() > 0) {
            sensor = sensors.get(0);
            running = sensorManager.registerListener(
                    sensorEventListener, sensor, 
                    SensorManager.SENSOR_DELAY_NORMAL);
            listener = orientationListener;
        }
    }
 
    /**
     * The listener that listen to events from the orientation listener
     */
    private static SensorEventListener sensorEventListener = 
        new SensorEventListener() {
 
        /** The side that is currently up */
        private Side currentSide = null;
        private Side oldSide = null;
        private float azimuth;
        private float pitch;
        private float roll;
 
        public void onAccuracyChanged(Sensor sensor, int accuracy) {}
 
        public void onSensorChanged(SensorEvent event) {
 
            azimuth = event.values[0];     // azimuth
            pitch = event.values[1];     // pitch
            roll = event.values[2];        // roll
 
            if (pitch < -45 && pitch > -135) {
                // top side up
                currentSide = Side.TOP;
            } else if (pitch > 45 && pitch < 135) {
                // bottom side up
                currentSide = Side.BOTTOM;
            } else if (roll > 45) {
                // right side up
                currentSide = Side.RIGHT;
            } else if (roll < -45) {
                // left side up
                currentSide = Side.LEFT;
            }
 
            if (currentSide != null && !currentSide.equals(oldSide)) {
                switch (currentSide) {
                    case TOP : 
                        listener.onTopUp();
                        break;
                    case BOTTOM : 
                        listener.onBottomUp();
                        break;
                    case LEFT: 
                        listener.onLeftUp();
                        break;
                    case RIGHT: 
                        listener.onRightUp();
                        break;
                }
                oldSide = currentSide;
            }
 
            // forwards orientation to the OrientationListener
            listener.onOrientationChanged(azimuth, pitch, roll);
        }
 
    };
 
}

OrientationManager trên có thể được dùng trong bất kỳ Activity hoặc Service nào:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package net.androgames.blog.sample.orientation;
 
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
 
/**
 * Android orientation sensor tutorial
 * @author antoine vianey
 * under GPL v3 : http://www.gnu.org/licenses/gpl-3.0.html
 */
public class Orientation extends Activity implements OrientationListener {
 
    private static Context CONTEXT;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        CONTEXT = this;
    }
 
    protected void onResume() {
        super.onResume();
        if (OrientationManager.isSupported()) {
            OrientationManager.startListening(this);
        }
    }
 
    protected void onDestroy() {
        super.onDestroy();
        if (OrientationManager.isListening()) {
            OrientationManager.stopListening();
        }
 
    }
 
    public static Context getContext() {
        return CONTEXT;
    }
 
    @Override
    public void onOrientationChanged(float azimuth, 
            float pitch, float roll) {
        ((TextView) findViewById(R.id.azimuth)).setText(
                String.valueOf(azimuth));
        ((TextView) findViewById(R.id.pitch)).setText(
                String.valueOf(pitch));
        ((TextView) findViewById(R.id.roll)).setText(
                String.valueOf(roll));
    }
 
    @Override
    public void onBottomUp() {
        Toast.makeText(this, "Bottom UP", 1000).show();
    }
 
    @Override
    public void onLeftUp() {
        Toast.makeText(this, "Left UP", 1000).show();
    }
 
    @Override
    public void onRightUp() {
        Toast.makeText(this, "Right UP", 1000).show();
    }
 
    @Override
    public void onTopUp() {
        Toast.makeText(this, "Top UP", 1000).show();
    }
 
}

Cách thường được dùng là đăng ký listener trong phương thức onResume() của Activity, và xóa trong phương thức onFinish().
Theo Androgames blog

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

Powered by WordPress | Designed by Elegant Themes