1 | /* |
2 | * Copyright (C) 2009 Pierre H�bert <pierrox@pierrox.net> |
3 | * http://www.pierrox.net/mcompass/ |
4 | * |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | * you may not use this file except in compliance with the License. |
7 | * You may obtain a copy of the License at |
8 | * |
9 | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | * |
11 | * Unless required by applicable law or agreed to in writing, software |
12 | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | * See the License for the specific language governing permissions and |
15 | * limitations under the License. |
16 | */ |
17 | |
18 | package net.pierrox.mcompass; |
19 | |
20 | import android.app.Activity; |
21 | import android.content.Context; |
22 | import android.content.Intent; |
23 | import android.content.SharedPreferences; |
24 | import it.unina.android.hardware.Sensor; |
25 | import it.unina.android.hardware.SensorEvent; |
26 | import it.unina.android.hardware.SensorEventListener; |
27 | import it.unina.android.hardware.SensorManager; |
28 | import android.opengl.GLSurfaceView; |
29 | import android.os.Bundle; |
30 | import android.preference.PreferenceManager; |
31 | import android.view.Menu; |
32 | import android.view.MenuItem; |
33 | import android.view.WindowManager; |
34 | import android.widget.LinearLayout; |
35 | import android.widget.TextView; |
36 | |
37 | public class MCompass extends Activity implements SensorEventListener { |
38 | private static final int MENU_SETTINGS=0; |
39 | private static final String KEY_DETAILS_PREFERENCE="details_preference"; |
40 | private static final String KEY_REVERSED_RING_PREFERENCE="reversed_ring_preference"; |
41 | private static final String KEY_FULLSCREEN_PREFERENCE="fullscreen_preference"; |
42 | |
43 | private CompassRenderer mCompassRenderer; |
44 | private GLSurfaceView mGLSurfaceView; |
45 | private TextView mHeadingView; |
46 | |
47 | private SensorManager mSensorManager; |
48 | private Sensor mOrientationSensor; |
49 | |
50 | // data for orientation values filtering (average using a ring buffer) |
51 | static private final int RING_BUFFER_SIZE=10; |
52 | private float[][][] mAnglesRingBuffer; |
53 | private int mNumAngles; |
54 | private int mRingBufferIndex; |
55 | private float[][] mAngles; |
56 | |
57 | |
58 | @Override |
59 | public void onCreate(Bundle savedInstanceState) { |
60 | super.onCreate(savedInstanceState); |
61 | |
62 | // set preferences default values |
63 | PreferenceManager.setDefaultValues(this, R.xml.preferences, false); |
64 | |
65 | // initialize the ring buffer for orientation values |
66 | mNumAngles=0; |
67 | mRingBufferIndex=0; |
68 | mAnglesRingBuffer=new float[RING_BUFFER_SIZE][3][2]; |
69 | mAngles=new float[3][2]; |
70 | mAngles[0][0]=0; |
71 | mAngles[0][1]=0; |
72 | mAngles[1][0]=0; |
73 | mAngles[1][1]=0; |
74 | mAngles[2][0]=0; |
75 | mAngles[2][1]=0; |
76 | |
77 | // the compass renderer manages 3D objects and gl surface life cycle |
78 | mCompassRenderer = new CompassRenderer(); |
79 | |
80 | // create views |
81 | mGLSurfaceView = new GLSurfaceView(this); |
82 | mGLSurfaceView.setRenderer(mCompassRenderer); |
83 | |
84 | mHeadingView = new TextView(this); |
85 | mHeadingView.setTextSize(30); |
86 | mHeadingView.setText(""); |
87 | mHeadingView.setBackgroundColor(0xffffffff); |
88 | mHeadingView.setTextColor(0xff000000); |
89 | |
90 | // layout the views in a vertical box |
91 | LinearLayout layout = new LinearLayout(this); |
92 | layout.setOrientation(LinearLayout.VERTICAL); |
93 | layout.addView(mHeadingView); |
94 | layout.addView(mGLSurfaceView); |
95 | |
96 | setContentView(layout); |
97 | |
98 | //mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); |
99 | mSensorManager = SensorManager.getInstance(getApplicationContext()); |
100 | mOrientationSensor=mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); |
101 | } |
102 | |
103 | @Override |
104 | protected void onResume() { |
105 | super.onResume(); |
106 | |
107 | // re-read preferences |
108 | SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); |
109 | int details; |
110 | String s=sharedPref.getString(KEY_DETAILS_PREFERENCE, "medium"); |
111 | if(s.equals("low")) { |
112 | details=0; |
113 | } else if(s.equals("high")) { |
114 | details=2; |
115 | } else { |
116 | details=1; |
117 | } |
118 | boolean reversedRing=sharedPref.getBoolean(KEY_REVERSED_RING_PREFERENCE, false); |
119 | mCompassRenderer.setParameters(details, reversedRing); |
120 | |
121 | int fullscreen_flag; |
122 | if(sharedPref.getBoolean(KEY_FULLSCREEN_PREFERENCE, false)) { |
123 | fullscreen_flag=WindowManager.LayoutParams.FLAG_FULLSCREEN; |
124 | } else { |
125 | fullscreen_flag=0; |
126 | } |
127 | getWindow().setFlags(fullscreen_flag, WindowManager.LayoutParams.FLAG_FULLSCREEN); |
128 | |
129 | mSensorManager.registerListener(this, mOrientationSensor, SensorManager.SENSOR_DELAY_GAME); |
130 | mGLSurfaceView.onResume(); |
131 | } |
132 | |
133 | @Override |
134 | protected void onPause() { |
135 | mGLSurfaceView.onPause(); |
136 | mSensorManager.unregisterListener(this); |
137 | super.onPause(); |
138 | } |
139 | |
140 | public void onSensorChanged(SensorEvent event) { |
141 | if(event.sensor==mOrientationSensor) { |
142 | if(mNumAngles==RING_BUFFER_SIZE) { |
143 | // subtract oldest vector |
144 | mAngles[0][0]-=mAnglesRingBuffer[mRingBufferIndex][0][0]; |
145 | mAngles[0][1]-=mAnglesRingBuffer[mRingBufferIndex][0][1]; |
146 | mAngles[1][0]-=mAnglesRingBuffer[mRingBufferIndex][1][0]; |
147 | mAngles[1][1]-=mAnglesRingBuffer[mRingBufferIndex][1][1]; |
148 | mAngles[2][0]-=mAnglesRingBuffer[mRingBufferIndex][2][0]; |
149 | mAngles[2][1]-=mAnglesRingBuffer[mRingBufferIndex][2][1]; |
150 | } else { |
151 | mNumAngles++; |
152 | } |
153 | |
154 | // convert angles into x/y |
155 | mAnglesRingBuffer[mRingBufferIndex][0][0]=(float) Math.cos(Math.toRadians(event.values[0])); |
156 | mAnglesRingBuffer[mRingBufferIndex][0][1]=(float) Math.sin(Math.toRadians(event.values[0])); |
157 | mAnglesRingBuffer[mRingBufferIndex][1][0]=(float) Math.cos(Math.toRadians(event.values[1])); |
158 | mAnglesRingBuffer[mRingBufferIndex][1][1]=(float) Math.sin(Math.toRadians(event.values[1])); |
159 | mAnglesRingBuffer[mRingBufferIndex][2][0]=(float) Math.cos(Math.toRadians(event.values[2])); |
160 | mAnglesRingBuffer[mRingBufferIndex][2][1]=(float) Math.sin(Math.toRadians(event.values[2])); |
161 | |
162 | // accumulate new x/y vector |
163 | mAngles[0][0]+=mAnglesRingBuffer[mRingBufferIndex][0][0]; |
164 | mAngles[0][1]+=mAnglesRingBuffer[mRingBufferIndex][0][1]; |
165 | mAngles[1][0]+=mAnglesRingBuffer[mRingBufferIndex][1][0]; |
166 | mAngles[1][1]+=mAnglesRingBuffer[mRingBufferIndex][1][1]; |
167 | mAngles[2][0]+=mAnglesRingBuffer[mRingBufferIndex][2][0]; |
168 | mAngles[2][1]+=mAnglesRingBuffer[mRingBufferIndex][2][1]; |
169 | |
170 | mRingBufferIndex++; |
171 | if(mRingBufferIndex==RING_BUFFER_SIZE) { |
172 | mRingBufferIndex=0; |
173 | } |
174 | |
175 | // convert back x/y into angles |
176 | float azimuth=(float) Math.toDegrees(Math.atan2((double)mAngles[0][1], (double)mAngles[0][0])); |
177 | float pitch=(float) Math.toDegrees(Math.atan2((double)mAngles[1][1], (double)mAngles[1][0])); |
178 | float roll=(float) Math.toDegrees(Math.atan2((double)mAngles[2][1], (double)mAngles[2][0])); |
179 | mCompassRenderer.setOrientation(azimuth, pitch, roll); |
180 | if(azimuth<0) azimuth=(360+azimuth)%360; |
181 | mHeadingView.setText(getString(R.string.heading)+": "+(int)azimuth+"°"); |
182 | } |
183 | } |
184 | |
185 | public void onAccuracyChanged(Sensor sensor, int accuracy) { |
186 | |
187 | } |
188 | |
189 | public boolean onCreateOptionsMenu(Menu menu) { |
190 | menu.add(0, MENU_SETTINGS, 0, R.string.settings).setIcon(android.R.drawable.ic_menu_preferences); |
191 | return true; |
192 | } |
193 | |
194 | public boolean onOptionsItemSelected(MenuItem item) { |
195 | switch (item.getItemId()) { |
196 | case MENU_SETTINGS : |
197 | Intent myIntent = new Intent(); |
198 | myIntent.setClassName(this, "net.pierrox.mcompass.Settings"); |
199 | startActivity(myIntent); |
200 | break; |
201 | } |
202 | return true; |
203 | } |
204 | } |