1/*
2 * Copyright 2012 AndroidPlot.com
3 *
4 *    Licensed under the Apache License, Version 2.0 (the "License");
5 *    you may not use this file except in compliance with the License.
6 *    You may obtain a copy of the License at
7 *
8 *        http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *    Unless required by applicable law or agreed to in writing, software
11 *    distributed under the License is distributed on an "AS IS" BASIS,
12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *    See the License for the specific language governing permissions and
14 *    limitations under the License.
15 */
16
17package com.androidplot.demos;
18
19import android.app.Activity;
20import android.content.Context;
21import android.graphics.Color;
22import android.hardware.Sensor;
23import android.hardware.SensorEvent;
24import android.hardware.SensorEventListener;
25import android.hardware.SensorManager;
26import android.os.Bundle;
27import android.view.View;
28import android.widget.CheckBox;
29import android.widget.CompoundButton;
30import com.androidplot.Plot;
31import com.androidplot.util.PlotStatistics;
32import com.androidplot.util.Redrawer;
33import com.androidplot.xy.*;
34import java.text.DecimalFormat;
35import java.util.Arrays;
36
37// Monitor the phone's orientation sensor and plot the resulting azimuth pitch and roll values.
38// See: http://developer.android.com/reference/android/hardware/SensorEvent.html
39public class OrientationSensorExampleActivity extends Activity implements SensorEventListener
40{
41
42    private static final int HISTORY_SIZE = 300;            // number of points to plot in history
43    private SensorManager sensorMgr = null;
44    private Sensor orSensor = null;
45
46    private XYPlot aprLevelsPlot = null;
47    private XYPlot aprHistoryPlot = null;
48
49    private CheckBox hwAcceleratedCb;
50    private CheckBox showFpsCb;
51    //private SimpleXYSeries aprLevelsSeries = null;
52    private SimpleXYSeries aLvlSeries;
53    private SimpleXYSeries pLvlSeries;
54    private SimpleXYSeries rLvlSeries;
55    private SimpleXYSeries azimuthHistorySeries = null;
56    private SimpleXYSeries pitchHistorySeries = null;
57    private SimpleXYSeries rollHistorySeries = null;
58
59    private Redrawer redrawer;
60
61    /** Called when the activity is first created. */
62    @Override
63    public void onCreate(Bundle savedInstanceState) {
64        super.onCreate(savedInstanceState);
65        setContentView(R.layout.orientation_sensor_example);
66
67        // setup the APR Levels plot:
68        aprLevelsPlot = (XYPlot) findViewById(R.id.aprLevelsPlot);
69        aprLevelsPlot.setDomainBoundaries(-1, 1, BoundaryMode.FIXED);
70        aprLevelsPlot.getGraphWidget().getDomainLabelPaint().setColor(Color.TRANSPARENT);
71
72        aLvlSeries = new SimpleXYSeries("A");
73        pLvlSeries = new SimpleXYSeries("P");
74        rLvlSeries = new SimpleXYSeries("R");
75
76        aprLevelsPlot.addSeries(aLvlSeries,
77                        new BarFormatter(Color.rgb(0, 200, 0), Color.rgb(0, 80, 0)));
78        aprLevelsPlot.addSeries(pLvlSeries,
79                        new BarFormatter(Color.rgb(200, 0, 0), Color.rgb(0, 80, 0)));
80        aprLevelsPlot.addSeries(rLvlSeries,
81                        new BarFormatter(Color.rgb(0, 0, 200), Color.rgb(0, 80, 0)));
82
83        aprLevelsPlot.setDomainStepValue(3);
84        aprLevelsPlot.setTicksPerRangeLabel(3);
85
86        // per the android documentation, the minimum and maximum readings we can get from
87        // any of the orientation sensors is -180 and 359 respectively so we will fix our plot's
88        // boundaries to those values.  If we did not do this, the plot would auto-range which
89        // can be visually confusing in the case of dynamic plots.
90        aprLevelsPlot.setRangeBoundaries(-180, 359, BoundaryMode.FIXED);
91
92        // update our domain and range axis labels:
93        aprLevelsPlot.setDomainLabel("");
94        aprLevelsPlot.getDomainLabelWidget().pack();
95        aprLevelsPlot.setRangeLabel("Angle (Degs)");
96        aprLevelsPlot.getRangeLabelWidget().pack();
97        aprLevelsPlot.setGridPadding(15, 0, 15, 0);
98        aprLevelsPlot.setRangeValueFormat(new DecimalFormat("#"));
99
100        // setup the APR History plot:
101        aprHistoryPlot = (XYPlot) findViewById(R.id.aprHistoryPlot);
102
103        azimuthHistorySeries = new SimpleXYSeries("Az.");
104        azimuthHistorySeries.useImplicitXVals();
105        pitchHistorySeries = new SimpleXYSeries("Pitch");
106        pitchHistorySeries.useImplicitXVals();
107        rollHistorySeries = new SimpleXYSeries("Roll");
108        rollHistorySeries.useImplicitXVals();
109
110        aprHistoryPlot.setRangeBoundaries(-180, 359, BoundaryMode.FIXED);
111        aprHistoryPlot.setDomainBoundaries(0, HISTORY_SIZE, BoundaryMode.FIXED);
112        aprHistoryPlot.addSeries(azimuthHistorySeries,
113                new LineAndPointFormatter(
114                        Color.rgb(100, 100, 200), null, null, null));
115        aprHistoryPlot.addSeries(pitchHistorySeries,
116                new LineAndPointFormatter(
117                        Color.rgb(100, 200, 100), null, null, null));
118        aprHistoryPlot.addSeries(rollHistorySeries,
119                new LineAndPointFormatter(
120                        Color.rgb(200, 100, 100), null, null, null));
121        aprHistoryPlot.setDomainStepMode(XYStepMode.INCREMENT_BY_VAL);
122        aprHistoryPlot.setDomainStepValue(HISTORY_SIZE/10);
123        aprHistoryPlot.setTicksPerRangeLabel(3);
124        aprHistoryPlot.setDomainLabel("Sample Index");
125        aprHistoryPlot.getDomainLabelWidget().pack();
126        aprHistoryPlot.setRangeLabel("Angle (Degs)");
127        aprHistoryPlot.getRangeLabelWidget().pack();
128
129        aprHistoryPlot.setRangeValueFormat(new DecimalFormat("#"));
130        aprHistoryPlot.setDomainValueFormat(new DecimalFormat("#"));
131
132        // setup checkboxes:
133        hwAcceleratedCb = (CheckBox) findViewById(R.id.hwAccelerationCb);
134        final PlotStatistics levelStats = new PlotStatistics(1000, false);
135        final PlotStatistics histStats = new PlotStatistics(1000, false);
136
137        aprLevelsPlot.addListener(levelStats);
138        aprHistoryPlot.addListener(histStats);
139        hwAcceleratedCb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
140            @Override
141            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
142                if(b) {
143                    aprLevelsPlot.setLayerType(View.LAYER_TYPE_NONE, null);
144                    aprHistoryPlot.setLayerType(View.LAYER_TYPE_NONE, null);
145                } else {
146                    aprLevelsPlot.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
147                    aprHistoryPlot.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
148                }
149            }
150        });
151
152        showFpsCb = (CheckBox) findViewById(R.id.showFpsCb);
153        showFpsCb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
154            @Override
155            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
156                levelStats.setAnnotatePlotEnabled(b);
157                histStats.setAnnotatePlotEnabled(b);
158            }
159        });
160
161        // get a ref to the BarRenderer so we can make some changes to it:
162        BarRenderer barRenderer = (BarRenderer) aprLevelsPlot.getRenderer(BarRenderer.class);
163        if(barRenderer != null) {
164            // make our bars a little thicker than the default so they can be seen better:
165            barRenderer.setBarWidth(25);
166        }
167
168        // register for orientation sensor events:
169        sensorMgr = (SensorManager) getApplicationContext().getSystemService(Context.SENSOR_SERVICE);
170        for (Sensor sensor : sensorMgr.getSensorList(Sensor.TYPE_ORIENTATION)) {
171            if (sensor.getType() == Sensor.TYPE_ORIENTATION) {
172                orSensor = sensor;
173            }
174        }
175
176        // if we can't access the orientation sensor then exit:
177        if (orSensor == null) {
178            System.out.println("Failed to attach to orSensor.");
179            cleanup();
180        }
181
182        sensorMgr.registerListener(this, orSensor, SensorManager.SENSOR_DELAY_UI);
183
184        redrawer = new Redrawer(
185                Arrays.asList(new Plot[]{aprHistoryPlot, aprLevelsPlot}),
186                100, false);
187    }
188
189    @Override
190    public void onResume() {
191        super.onResume();
192        redrawer.start();
193    }
194
195    @Override
196    public void onPause() {
197        redrawer.pause();
198        super.onPause();
199    }
200
201    @Override
202    public void onDestroy() {
203        redrawer.finish();
204        super.onDestroy();
205    }
206
207    private void cleanup() {
208        // aunregister with the orientation sensor before exiting:
209        sensorMgr.unregisterListener(this);
210        finish();
211    }
212
213
214    // Called whenever a new orSensor reading is taken.
215    @Override
216    public synchronized void onSensorChanged(SensorEvent sensorEvent) {
217
218        // update level data:
219        aLvlSeries.setModel(Arrays.asList(
220                new Number[]{sensorEvent.values[0]}),
221                SimpleXYSeries.ArrayFormat.Y_VALS_ONLY);
222
223        pLvlSeries.setModel(Arrays.asList(
224                        new Number[]{sensorEvent.values[1]}),
225                        SimpleXYSeries.ArrayFormat.Y_VALS_ONLY);
226
227        rLvlSeries.setModel(Arrays.asList(
228                        new Number[]{sensorEvent.values[2]}),
229                        SimpleXYSeries.ArrayFormat.Y_VALS_ONLY);
230
231        // get rid the oldest sample in history:
232        if (rollHistorySeries.size() > HISTORY_SIZE) {
233            rollHistorySeries.removeFirst();
234            pitchHistorySeries.removeFirst();
235            azimuthHistorySeries.removeFirst();
236        }
237
238        // add the latest history sample:
239        azimuthHistorySeries.addLast(null, sensorEvent.values[0]);
240        pitchHistorySeries.addLast(null, sensorEvent.values[1]);
241        rollHistorySeries.addLast(null, sensorEvent.values[2]);
242    }
243
244
245    @Override
246    public void onAccuracyChanged(Sensor sensor, int i) {
247        // Not interested in this event
248    }
249}