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}