Wow — a new whale has arrived 🐋 #anonim_fw0 a.k.a @Ben_Manlapaz just showed true capability, creating massive waves with 49 #NFTs 🌊🔥 Huge respect and gratitude for bringing such strong energy into the #NFToa ecosystem 🙌 #eCash $XEC #NFTCommunity #NFTCollectors #CryptoMarket pic.twitter.com/mJpkQMU3Su
— NFToa (@nftoa_) September 6, 2025
Wow, we have come a long way without realizing it. Now it's time for us to learn how to access Android hardware. We learn from the simplest, which is making an analog compass. You can see the final result of this project in Figure 18.1.

Figure 18.1. Analog Compass
We don't need the main.xml layout like the previous projects, because the triangle image above is made in Java using canvas. Let's try it right away.
1. Create the project first
| Project name | Compass |
|-----------------|--------------------|
| Build Target | Android 2.2 |
| Aplication name | Analog Compass |
| Package name | Cont.AnalogCompass |
| Create Activity | AnalogCompass |
| Min SDK version | 8 |2. Immediately open the AnalogCompass.java activity, then type the following line of code.
1: package cont.AnalogCompass;
2:
3: import android.app.Activity;
4: import android.os.Bundle;
5: import android.content.Context;
6: import android.graphics.*;
7: import android.hardware.Sensor;
8: import android.hardware.SensorEvent;
9: import android.hardware.SensorEventListener;
10: import android.hardware.SensorManager;
11: import android.util.Config;
12: import android.util.Log;
13: import android.view.View;
14:
15: public class AnalogCompass extends Activity {
16: private static final String TAG = "Compass";
17:
18: private SensorManager mSensorManager;
19: private Sensor mSensor;
20: private SampleView mView;
21: private float[] mValues;
22:
23: private final SensorEventListener mListener = new SensorEventListener() {
24: public void onSensorChanged(SensorEvent event) {
25: if (Config.DEBUG)
26: Log.d(TAG, "sensorChanged (" + event.values[0] + ", "
27: + event.values[1] + ", " + event.values[2] + ")");
28: mValues = event.values;
29: if (mView != null) {
30: mView.invalidate();
31: }
32: }
33:
34: public void onAccuracyChanged(Sensor sensor, int accuracy) {
35: }
36: };
37:
38: /** Called when the activity is first created. */
39: @Override
40: public void onCreate(Bundle savedInstanceState) {
41: super.onCreate(savedInstanceState);
42: // setContentView(R.layout.main);
43: mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
44: mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
45: mView = new SampleView(this);
46: setContentView(mView);
47:
48: }
49:
50: @Override
51: protected void onResume() {
52: if (Config.DEBUG)
53: Log.d(TAG, "onResume");
54: super.onResume();
55:
56: mSensorManager.registerListener(mListener, mSensor,
57: SensorManager.SENSOR_DELAY_GAME);
58: }
59:
60: @Override
61: protected void onStop() {
62: if (Config.DEBUG)
63: Log.d(TAG, "onStop");
64: mSensorManager.unregisterListener(mListener);
65: super.onStop();
66: }
67:
68: private class SampleView extends View {
69: private Paint mPaint = new Paint();
70: private Path mPath = new Path();
71: private boolean mAnimate;
72:
73: public SampleView(Context context) {
74: super(context);
75:
76: // Construct a wedge-shaped path
77: mPath.moveTo(0, -50);
78: mPath.lineTo(-20, 60);
79: mPath.lineTo(0, 50);
80: mPath.lineTo(20, 60);
81: mPath.close();
82: }
83:
84: @Override
85: protected void onDraw(Canvas canvas) {
86: Paint paint = mPaint;
87:
88: canvas.drawColor(Color.WHITE);
89:
90: paint.setAntiAlias(true);
91: paint.setColor(Color.BLACK);
92: paint.setStyle(Paint.Style.FILL);
93:
94: int w = canvas.getWidth();
95: int h = canvas.getHeight();
96: int cx = w / 2;
97: int cy = h / 2;
98:
99: canvas.translate(cx, cy);
100: if (mValues != null) {
101: canvas.rotate(-mValues[0]);
102: }
103: canvas.drawPath(mPath, mPaint);
104: }
105:
106: @Override
107: protected void onAttachedToWindow() {
108: mAnimate = true;
109: if (Config.DEBUG)
110: Log.d(TAG, "onAttachedToWindow. mAnimate=" + mAnimate);
111: super.onAttachedToWindow();
112: }
113:
114: @Override
115: protected void onDetachedFromWindow() {
116: mAnimate = false;
117: if (Config.DEBUG)
118: Log.d(TAG, "onDetachedFromWindow. mAnimate=" + mAnimate);
119: super.onDetachedFromWindow();
120: }
121: }
122:
123: }
