You are on page 1of 7

GetyourappstoworkwiththeXperiaactivepressuresensor

Acoupleofweeksago,SonyEricssonannouncedthenewXperiaactiveacompactAndroid smartphonedesignedforconsumerswithanactivelifestyle.AtrulyuniquefeatureoftheXperia activeliesinitspressuresensorforbarometricmeasuring.Developerscanusethissensorinapps,by accessingitthroughtheAndroidsensorAPI. Thistutorialprovidessometipsandcodeexamplestogetyourapptoworkwiththepressuresensor. Thepressuresensorcanbeusedtogeneratedatainputforappssuchasweatherlogs,barometric appsorsimilar.Inthistutorial,youwilllearnhowanappcanmakeuseofthepressuresensor.Thisis easilydoneinyourAndroiddevelopmentenvironment. Learningthebasics Inthefollowingsection,wewilldescribehowtocreateasimpleappthatisreadingdatafromthe pressuresensoranddisplayingitinasimpletextview.Youcanobviouslycreatemuchmorecomplex UIsyourselftodisplaythisinformation. Firstofall,youmusthaveanactivity,tohavesomethingtodisplay.
public class PressureSensorDemo extends Activity implements SensorEventListener{

:
Asaconvenience,theactivityimplementsthesensorlistenerinterface.Yourappwillconnecttothe sensoritselfusingthenormalsensorinterface.ThiscanbedonebytheonCreate()method.
/** Called when the activity is first created. */

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); outView = (TextView) findViewById(R.id.output); // Real sensor manager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); pressureDataList = new ArrayList<PressuredataObject>();

Afterthis,yourappneedstoregisteritselfasaSensorEventListener.Inthiscase,wewilldoitby overwritingtheonResumemethod.
protected void onResume() { super.onResume(); Log.d(TAG, "onResume"); sensorManager.registerListener(this, pressureSensor, SensorManager.SENSOR_DELAY_NORMAL); }

Finally,yourapplicationwillneedtoimplementtheSensorEventListenerinterfacemethods.
@Override public void onAccuracyChanged(Sensor sensor, int arg1) { // TODO Auto-generated method stub if (sensor.equals(pressureSensor)){ Log.d(LOG_TAG,"Accuracy changed on Pressure Sensor"); } else{ Log.d(LOG_TAG,"Accuracy changed on Other Sensor, odd beahaviour"); } } @Override public void onSensorChanged(SensorEvent sensEvent) { // TODO Auto-generated method stub float [] values = sensEvent.values; StringBuilder sb = new StringBuilder("Received Values are: \n"); for (int i = 0; i < values.length; i++) { sb.append(values [i] + "\n"); } String s1 = sb.toString(); Log.d(LOG_TAG,s1); outView.setText(s1); }

Somethingalittlebitmorethenthebasics Another,andperhapsmoreusefulapproach,couldbetoletaservicelogthedatafromthepressure

sensortoacontentprovider.Youshouldprobablyconsidertakingafew(betweenfiveorten) samples,andselectthemedianvaluetominimiseimpactoftransientvalues.Transientvaluescan occursuddenly,withtemporarypeakvaluesbeingvisibleduringverysmalltimeframes,forexample whenadoorclosingwhileapressurevalueisconnected.Anotherexamplecouldbeapuffofair hittingthedetector. Asanextstep,wewillbuildasmallloggersystemwhereaservicecollectingairpressuredatais running.Theserviceistriggeredtorunfromthestartingactivityfirst,anditisthenrestartedat certainintervalsusingtheAlarmManager. Buildingaloggersystem Tostartwith,wewillimplementtheactualdatacollectionasasimpleclass,whichstartsaseparate threadbyimplementingtheRunnableinterface.Thisisdoneinordertobeabletoreceiveanumber ofcallbackstotheSensorListener. Thedatacollectingclassisinitializedandrunfromaservice.Ittakesfivesamples,insertsthemina list,andselectsthemedianvaluetobestoredinacontentprovider.Thecontentprovideriscalled fromautilityclasswhichwewillnotdescribefurtherhere,sincetherearetonsofexamplesonthe Internetonhowtocreateacontentprovider. However,whenthedatacollectingclasshaswrittentothecontentprovidersuccessfully,theAlarm Managerisnotifiedinordertosendabroadcastintentintenminutes.Itwillthenwakeupthedevice tomakesureasampleisloggedeverytenminutes.ThebroadcastintentisreceivedinaBroadcast receiver(findadescriptionofitbelow).TheserviceisstoppedusingstopSelfwhenthedata collectionisdone.Thisiswhatitlookslike:
private class DataCollector implements SensorEventListener, Runnable{ private static final String LOG_TAG = "DataCollectorthread"; private Sensor pressureSensor; private Thread thr; private ArrayList<PressuredataObject> pressureDataList = null; private int numReads; private DataCollector() { thr = new Thread(this); } public void collectData(){ thr.start(); } @Override public void run() { // TODO Auto-generated method stub SensorManager sensorManager = SensorManager)getSystemService(SENSOR_SERVICE); pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); pressureDataList = newArrayList<PressuredataObject>(); sensorManager.registerListener(this, pressureSensor, SensorManager.SENSOR_DELAY_NORMAL); while (numReads < PressureUtilities.MAXLENGTHOFLIST){ try { Thread.sleep(1000); } catch (InterruptedException e) {

System.out.println("Timeout " + numReads); } sensorManager.unregisterListener(this); PressuredataObject pdo = PressureUtilities.selectMedianValue(pressureDataList); if (PressureUtilities.insertPressureObjectToDB(PressureSensorService.this,pdo) != -1){ //If database is not full set a new time next time to take sample. AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); Intent it = new Intent("com.sonyericsson.examples.pressuresensor.sendbroadcast"); PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 5, it, PendingIntent.FLAG_CANCEL_CURRENT ); long now = System.currentTimeMillis(); long alarmTime = now + (1000 * 60 * 10); //Delay alarm 5 seconds, 10 minutes alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, pi); //Repeat once every minute } else{ Log.v(LOG_TAG, "Database is full"); } wake_lock.release(); stopSelf(); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-generated method stub } } @Override public void onSensorChanged(SensorEvent sensEvent) { // TODO Auto-generated method stub float [] values = sensEvent.values; PressureUtilities.insertPressureObjectToList(new PressuredataObject(values[0], DateFormat.getTimeFormat(getApplicationContext()).format( Calendar.getInstance().getTime())),pressureDataList ); Log.d(LOG_TAG,"Received and stored event" + numReads); numReads++; } }

Nowyouhavetomakeyourserviceinitiateandrunthedatacollection.Thisisdonebyinitiatinga newinstanceofDataCollectorclassandorderingittocollectdataatreceptionofthe onStartCommandmethod.

public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); wake_lock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PressureData"); wake_lock.acquire(); DataCollector dataCollector = new DataCollector(); dataCollector.collectData(); return startId; }

Asyoucansee,theserviceacquiresapartialwakelockwhenitisstarted.Thewakelockisreleased whentheservicetaskisfinished.Ifyouhaveaservicehandlingmorethanonetask,taskbranching shouldbeconsidered.Inthisexample,theBroadcastreceiverdoesnotplayaverybigrole.Basically itonlystartstheservice.


public class PressureSensorBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context ctxt, Intent intent) { // TODO Auto-generated method stub PowerManager pm = (PowerManager) ctxt.getSystemService(Context.POWER_SERVICE); WakeLock wake_lock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PressureData"); wake_lock.acquire(); Intent serviceIntent = new Intent(ctxt, PressureSensorService.class); ctxt.startService(serviceIntent); wake_lock.release(); } }

Pleasenotethatthebroadcastreceiverisrunningwithinawakelock.Whatyouneedtodo,istoset upthemanifestfiletohandletheservice,broadcastreceiver,contentprovider.Also,dontforgetthe permissions! Example:


<manifest xmlns:android="http://schemas.android.com/apk/res/android" <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>

<application android:icon="@drawable/icon" android:label="@string/app_name"> : <provider android:name=".db.PressureSensorDataProvider" android:authorities="com.sonyericsson.developerworld.example.pressuresensor .db" /> <receiver android:name=".PressureSensorBroadcastReceiver"> <intent-filter> <action android:name="com.sonyericsson.examples.pressuresensor.sendbroadcast" /> </intent-filter> </receiver> <service android:name ="PressureSensorService"> <intent-filter> <action android:name = ".PressureSensorService"/> </intent-filter> </service> </application> </manifest>

IfyouwanttolearnmoreabouttheAlarmManager,checkoutAndroidsAlarmManagerreferences. YoucanalsofindthisAlarmManagertutorialandotherresourcesontheInternet. Nowyouneedtofindawaytodisplayyourdata.However,weleavethisuptoyousincethereareso manywaystodothis.Butwedidsometesttodrawthevaluestothecanvasofaview,withsome adjustmentstomakeagraphdisplayvalueswithinafairvaluerange.Onethingtokeepinmindwhile doingthis,isthatnormalairpressuremostoftenlieswithin980~1030mBarorsoonsealevel(1 mBaris1hPa). Verifyingyourpressuresensorapplication Now,havingcreatedanappthatmakesuseofthepressuresensor,youareobviouslyinterestedin verifyingitall.ThebestwaytoverifyyourapplicationisofcoursetouseanXperiaactivedevice. Butasyoumightknow,Xperiaactiveisstillnotavailableinstores.Butuntilthen,thereisawayto dosomeverificationanyhowwithabitoftweakinginyourcode! Normallyyourtypicalappconsistsofatleasttwoparts.Onepartthatcollectsdata,andonelogical partthatdisplaysthedata.Inthiscase,itistrickytoverifythecollectionofdata,butyoucanverify howthedataisdisplayed.Whatyoucando,istofeedthedatausinganothersensor,perhapsthe accelerometer,andadjustthevaluestotheappropriateairpressure.Youcanthenusethisdataas input.Sincetheaccelerometertendstogivevaluesbetween+10to10,itisroughlyamatterof adding1013tothesensorvaluetogetappropriatevalues. Whatappscanyoucreateusingthepressuresensor? Wethinkitisgoingtobereallyinterestingtoseewhatkindofappsthatwillmakeuseofthissensor. Whenbrainstorming,wecouldforexampleimagineacrowdsourceweatherdatacollectionservice, whereuserssendinbarometricdatatoacentralserver(usingtextmessages,emailetc)within certaintimeintervals.

Anothercoolideaistousethepressuresensortocalculatealtitude,forexample,changesinpressure relativetothealtitude.Belowisaknownformuladescribinghowtocalculatethealtitude.

PressuretoAltitudeConversion(Troposphere) 1976USStandardAtmosphereisbasedontheassumptions: ZeroaltitudepressureP0=101325[Pa](=1013.25mbar) ZeroaltitudetemperatureT0=288.15K TemperaturegradientTgradient=6.5/1000[K/m]inthetroposphere Temperatureinthestratosphere=56.46C RisthespecificgasconstantR=R*/M0R=287.052[J/(K*kg)] 100Pa=1mbar

Analtitudechangeof8metreswillroughlygivea1mBardifference.Athigheraltitudes,thepressure willbelower.Thiscouldforexamplebereallyinterestinginworkoutsessions.Incombinationwith theGPS,someinterestingservicescanprobablybecreatedthisisonlylimitedbyyourcreativity! Ifyouwanttomoreaboutpressure,checkoutthemathematicsanddatainWikipediasAtmospheric pressurearticle.

You might also like