This is a simple app that displays all the sensors in the phone reporting the following characteristics:
- Name: name of the sensor
- Version: version of the sensor’s module
- Vendor: vendor of this sensor
- Type: type of this sensor
- Max Range: maximum range of the sensor
- Resolution: resolution of the sensor
- Min Delay: minimum delay allowed between two events (equals to zero if this sensor only returns a value when the data it’s measuring changes)
- Power: the power of the sensor
-
- create an Android project with package eu.lucazanini.sensorlist and without a starting activity
- replace the file AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="eu.lucazanini.sensorlist" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="5" android:targetSdkVersion="16" /> <application android:icon="@drawable/ic_launcher" android:theme="@style/AppTheme" android:label="@string/app_name"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
- replace the file res/values/strings.xml
<resources> <string name="app_name">Sensor List</string> <string name="hello_world">Hello world!</string> <string name="menu_settings">Settings</string> <string name="name_label">Name</string> <string name="vendor_label">Vendor</string> <string name="default_text">not found</string> <string name="type_label">Type</string> <string name="version_label">Version</string> <string name="maximum_range_label">Max Range</string> <string name="min_delay_label">Min Delay</string> <string name="resolution_label">Resolution</string> <string name="power_label">Power</string> </resources>
- create the file res/values/types.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="accelerometer">accelerometer sensor</string> <string name="ambient_temperature">ambient temperature sensor</string> <string name="gravity">gravity sensor</string> <string name="gyroscope">gyroscope sensor</string> <string name="light">light sensor</string> <string name="linear_acceleration">linear acceleration sensor</string> <string name="magnetic_field">magnetic field sensor</string> <string name="orientation">orientation sensor (deprecated)</string> <string name="pressure">pressure sensor</string> <string name="proximity">proximity sensor</string> <string name="relative_humidity">relative humidity sensor</string> <string name="rotation_vector">rotation vector sensor</string> <string name="temperature">temperature sensor (deprecated)</string> <string name="unknown">unknown sensor</string> </resources>
- replace the file res/values/styles.xml
<resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="AppTheme" parent="android:Theme.Light" /> <style name="TitleLabel" parent="@android:style/Widget.TextView"> <item name="android:textStyle">italic</item> <item name="android:textSize">14sp</item> </style> <style name="BodyLabel" parent="@android:style/Widget.TextView"> <item name="android:textStyle">italic</item> <item name="android:textSize">12sp</item> </style> <style name="TitleView" parent="@android:style/Widget.TextView"> <item name="android:textStyle">bold</item> <item name="android:textSize">14sp</item> </style> <style name="BodyView" parent="@android:style/Widget.TextView"> <item name="android:textSize">12sp</item> </style> </resources>
in this file .xml I set 4 custom styles for the views so labels are in italic and the fields more important are in bold and with a larger font
- create the resource res/layout/list_item.xml
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="10sp" android:paddingBottom="10sp" > <TextView android:id="@+id/nameLabel" style="@style/TitleLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_marginLeft="10dp" android:text="@string/name_label" /> <TextView android:id="@+id/vendorLabel" style="@style/TitleLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/nameLabel" android:layout_below="@id/nameLabel" android:text="@string/vendor_label" /> <TextView android:id="@+id/typeLabel" style="@style/BodyLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/vendorLabel" android:layout_below="@id/vendorLabel" android:text="@string/type_label" /> <TextView android:id="@+id/maximumRangeLabel" style="@style/BodyLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/typeLabel" android:layout_below="@id/typeLabel" android:text="@string/maximum_range_label" /> <TextView android:id="@+id/resolutionLabel" style="@style/BodyLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/maximumRangeLabel" android:layout_below="@id/maximumRangeLabel" android:text="@string/resolution_label" /> <TextView android:id="@+id/minDelayLabel" style="@style/BodyLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/resolutionLabel" android:layout_below="@id/resolutionLabel" android:text="@string/min_delay_label" /> <TextView android:id="@+id/powerLabel" style="@style/BodyLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/minDelayLabel" android:layout_below="@id/minDelayLabel" android:text="@string/power_label" /> <TextView android:id="@+id/nameView" style="@style/TitleView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/nameLabel" android:layout_alignBottom="@id/nameLabel" android:layout_marginLeft="40dp" android:layout_toRightOf="@id/nameLabel" android:singleLine="true" android:text="@string/default_text" /> <TextView android:id="@+id/versionLabel" style="@style/BodyLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/nameView" android:layout_alignBottom="@id/nameView" android:layout_marginLeft="10dp" android:layout_toRightOf="@id/nameView" android:text="@string/version_label" /> <TextView android:id="@+id/vendorView" style="@style/TitleView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/vendorLabel" android:layout_alignBottom="@id/vendorLabel" android:layout_alignLeft="@id/nameView" android:singleLine="true" android:text="@string/default_text" /> <TextView android:id="@+id/typeView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/typeLabel" android:layout_alignBottom="@id/typeLabel" android:layout_alignLeft="@id/nameView" android:text="@string/default_text" /> <TextView android:id="@+id/versionView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/versionLabel" android:layout_alignBottom="@id/versionLabel" android:layout_marginLeft="10dp" android:layout_toRightOf="@id/versionLabel" android:text="@string/default_text" /> <TextView android:id="@+id/maximumRangeView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/maximumRangeLabel" android:layout_alignBottom="@id/maximumRangeLabel" android:layout_alignLeft="@id/nameView" android:text="@string/default_text" /> <TextView android:id="@+id/unitsRangeView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/maximumRangeView" android:layout_alignBottom="@id/maximumRangeView" android:layout_marginLeft="2dp" android:layout_toRightOf="@id/maximumRangeView" android:text="" /> <TextView android:id="@+id/minDelayView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/minDelayLabel" android:layout_alignBottom="@id/minDelayLabel" android:layout_alignLeft="@id/nameView" android:text="@string/default_text" /> <TextView android:id="@+id/unitsDelayView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/minDelayView" android:layout_alignBottom="@id/minDelayView" android:layout_marginLeft="2dp" android:layout_toRightOf="@id/minDelayView" android:text="" /> <TextView android:id="@+id/powerView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/powerLabel" android:layout_alignBottom="@id/powerLabel" android:layout_alignLeft="@id/nameView" android:text="@string/default_text" /> <TextView android:id="@+id/unitsPowerView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/powerView" android:layout_alignBottom="@id/powerView" android:layout_marginLeft="2dp" android:layout_toRightOf="@id/powerView" android:text="" /> <TextView android:id="@+id/resolutionView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/resolutionLabel" android:layout_alignBottom="@id/resolutionLabel" android:layout_alignLeft="@id/nameView" android:text="@string/default_text" /> <TextView android:id="@+id/unitsResolutionView" style="@style/BodyView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBaseline="@id/resolutionView" android:layout_alignBottom="@id/resolutionView" android:layout_marginLeft="2dp" android:layout_toRightOf="@id/resolutionView" android:text="" /> </RelativeLayout> </HorizontalScrollView>
this layout is a single item of the ListView in which you see the details of only one sensor
the views in this layout point to the styles defined in res/values/styles.xml - create the class eu/lucazanini/sensorlist/MainActivity.java
package eu.lucazanini.sensorlist; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import android.app.ListActivity; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; public class MainActivity extends ListActivity implements SensorEventListener { private SensorAdapter adapter; private List<MySensor> sensorList; public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); sensorList = new ArrayList<MySensor>(); sensorList = getSensors(); adapter = new SensorAdapter(this, R.layout.list_item, sensorList); setListAdapter(adapter); } public void onSensorChanged(SensorEvent event) { } private List<MySensor> getSensors() { List<MySensor> list = new ArrayList<MySensor>(); SensorManager sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE); List<Sensor> phoneSensor = sm.getSensorList(Sensor.TYPE_ALL); Iterator<Sensor> it = phoneSensor.iterator(); while (it.hasNext()) { Sensor s = it.next(); list.add(new MySensor(s, getApplicationContext())); } return list; } }
the main activity extends the class ListActivity and not Activity, because it is more easy to display a list of items
in the onCreate event there are 3 fundamental steps:
-
-
- I create an ArrayList<MySensor>, that it is an array containing the Sensor objects that are the sensors of the phone
- I create a SensorAdapter object, in whose constructor I also pass the ArrayList<MySensor> of the previous step; it is important that SensorAdapter extends ArrayAdapter<MySensor>
- I pass the SensorAdapter object as argument to setListAdapter to fill the ListView
-
in the getSensors event I find all the sensors of the phone and I add them as objects of the class MySensor to a List that I set to ArrayList<MySensor> in the onCreate event
- create the class eu/lucazanini/sensorlist/SensorAdapter.java
package eu.lucazanini.sensorlist; import java.util.List; import android.content.Context; import android.os.Build; import android.text.Html; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.TextView; public class SensorAdapter extends ArrayAdapter<MySensor> { private static final int SDK = Build.VERSION.SDK_INT; private int resource; public SensorAdapter(Context context, int resource, List<MySensor> items) { super(context, resource, items); this.resource = resource; } @Override public View getView(int position, View convertView, ViewGroup parent) { LinearLayout newView; if (convertView == null) { newView = new LinearLayout(getContext()); String inflater = Context.LAYOUT_INFLATER_SERVICE; LayoutInflater li; li = (LayoutInflater) getContext().getSystemService(inflater); li.inflate(resource, newView, true); } else { newView = (LinearLayout) convertView; } TextView nameView = (TextView) newView.findViewById(R.id.nameView); TextView vendorView = (TextView) newView.findViewById(R.id.vendorView); TextView typeView = (TextView) newView.findViewById(R.id.typeView); TextView versionView = (TextView) newView .findViewById(R.id.versionView); TextView maximumRangeView = (TextView) newView .findViewById(R.id.maximumRangeView); TextView minDelayView = (TextView) newView .findViewById(R.id.minDelayView); TextView powerView = (TextView) newView.findViewById(R.id.powerView); TextView resolutionView = (TextView) newView .findViewById(R.id.resolutionView); TextView unitsRangeView = (TextView) newView .findViewById(R.id.unitsRangeView); TextView unitsResolutionView = (TextView) newView .findViewById(R.id.unitsResolutionView); TextView unitsDelayView = (TextView) newView .findViewById(R.id.unitsDelayView); TextView unitsPowerView = (TextView) newView .findViewById(R.id.unitsPowerView); if (SDK < Build.VERSION_CODES.GINGERBREAD) { TextView minDelayLabel = (TextView) newView .findViewById(R.id.minDelayLabel); minDelayLabel.setVisibility(View.GONE); minDelayView.setVisibility(View.GONE); unitsDelayView.setVisibility(View.GONE); } MySensor mySensor = getItem(position); nameView.setText(mySensor.getName()); vendorView.setText(mySensor.getVendor()); typeView.setText(mySensor.getTypeDescription()); versionView.setText(String.valueOf(mySensor.getVersion())); maximumRangeView.setText(String.valueOf(mySensor.getMaximumRange())); if (SDK >= Build.VERSION_CODES.GINGERBREAD) minDelayView.setText(String.valueOf(mySensor.getMinDelay())); powerView.setText(String.valueOf(mySensor.getPower())); resolutionView.setText(String.format("%f", mySensor.getResolution())); unitsRangeView.setText(Html.fromHtml(mySensor.getUnits())); unitsResolutionView.setText(Html.fromHtml(mySensor.getUnits())); if (SDK >= Build.VERSION_CODES.GINGERBREAD) unitsDelayView.setText(Html.fromHtml(mySensor.getDelayUnits())); unitsPowerView.setText(Html.fromHtml(mySensor.getPowerUnits())); return newView; } }
when you extend an ArrayAdapter, you override the method getView to set the layout (res/layout/list_item.xml)
I display and set the text views related to “Min Delay” only if the API level is equal to or greater than Gingerbread
some strings are displayed using the method Html.fromHtml(String source) because they contain special characters (μ or ²) - create the class eu/lucazanini/sensorlist/MySensor.java
package eu.lucazanini.sensorlist; import android.annotation.TargetApi; import android.content.Context; import android.hardware.Sensor; import android.os.Build; public class MySensor { private final static String MICRO = "&#x3BC;"; private static final int SDK = Build.VERSION.SDK_INT; private final static String SQUARE = "&#xB2;"; private Context context; private float maximumRange, minDelay, power, resolution; private String name, vendor; private int type, version; @TargetApi(Build.VERSION_CODES.GINGERBREAD) public MySensor(Sensor sensor, Context context) { this.name = sensor.getName(); this.vendor = sensor.getVendor(); this.type = sensor.getType(); this.version = sensor.getVersion(); this.maximumRange = sensor.getMaximumRange(); if (SDK >= Build.VERSION_CODES.GINGERBREAD) this.minDelay = sensor.getMinDelay(); this.power = sensor.getPower(); this.resolution = sensor.getResolution(); this.context = context; } public String getDelayUnits() { return MICRO + "s"; } public float getMaximumRange() { return maximumRange; } public float getMinDelay() { return minDelay; } public String getName() { return name; } public float getPower() { return power; } public String getPowerUnits() { return "mA"; } public float getResolution() { return resolution; } public int getType() { return type; } public String getTypeDescription() { String description = null; switch (type) { case Sensor.TYPE_ACCELEROMETER: description = context.getResources().getString( R.string.accelerometer); break; case Sensor.TYPE_AMBIENT_TEMPERATURE: description = context.getResources().getString( R.string.ambient_temperature); break; case Sensor.TYPE_GRAVITY: description = context.getResources().getString(R.string.gravity); break; case Sensor.TYPE_GYROSCOPE: description = context.getResources().getString(R.string.gyroscope); break; case Sensor.TYPE_LIGHT: description = context.getResources().getString(R.string.light); break; case Sensor.TYPE_LINEAR_ACCELERATION: description = context.getResources().getString( R.string.linear_acceleration); break; case Sensor.TYPE_MAGNETIC_FIELD: description = context.getResources().getString( R.string.magnetic_field); break; case Sensor.TYPE_ORIENTATION: description = context.getResources() .getString(R.string.orientation); break; case Sensor.TYPE_PRESSURE: description = context.getResources().getString(R.string.pressure); break; case Sensor.TYPE_PROXIMITY: description = context.getResources().getString(R.string.proximity); break; case Sensor.TYPE_RELATIVE_HUMIDITY: description = context.getResources().getString( R.string.relative_humidity); break; case Sensor.TYPE_ROTATION_VECTOR: description = context.getResources().getString( R.string.rotation_vector); break; case Sensor.TYPE_TEMPERATURE: description = context.getResources() .getString(R.string.temperature); break; default: description = context.getResources().getString(R.string.unknown); break; } return description; } public String getUnits() { String units = null; switch (type) { case Sensor.TYPE_ACCELEROMETER: units = "m/s" + SQUARE; break; case Sensor.TYPE_AMBIENT_TEMPERATURE: units = "°C"; break; case Sensor.TYPE_GRAVITY: units = "m/s" + SQUARE; break; case Sensor.TYPE_GYROSCOPE: units = "rad/s"; break; case Sensor.TYPE_LIGHT: units = "SI lux"; break; case Sensor.TYPE_LINEAR_ACCELERATION: units = "m/s" + SQUARE; break; case Sensor.TYPE_MAGNETIC_FIELD: units = MICRO + "T"; break; case Sensor.TYPE_ORIENTATION: units = "°"; break; case Sensor.TYPE_PRESSURE: units = "hPa"; break; case Sensor.TYPE_PROXIMITY: units = "cm"; break; case Sensor.TYPE_RELATIVE_HUMIDITY: units = ""; break; case Sensor.TYPE_ROTATION_VECTOR: units = ""; break; case Sensor.TYPE_TEMPERATURE: units = "°C"; break; default: units = "unknown"; break; } return units; } public String getVendor() { return vendor; } public int getVersion() { return version; } public void setMaximumRange(float maximumRange) { this.maximumRange = maximumRange; } public void setMinDelay(float minDelay) { this.minDelay = minDelay; } public void setName(String name) { this.name = name; } public void setPower(float power) { this.power = power; } public void setResolution(float resolution) { this.resolution = resolution; } public void setType(int type) { this.type = type; } public void setVendor(String vendor) { this.vendor = vendor; } public void setVersion(int version) { this.version = version; } @Override public String toString() { return name; } }
the method getMinDelay of the class Sensor is new with GingerBread (API 9, Android 2.3), then you can use it only after the condition that the API level of the device is equal to or greater than 9
the annotation @TargetApi avoids a compilation error
the variables MICRO e SQUARE define some special characters in the method Html.fromHtml(String source) of the class SensorAdapter
The app running on emulator with API Level 7
The app running on emulator with API Level 17
The app running on Galaxy Nexus with API Level 17
The icon is different from the default one because I have replaced the icons ic_launcher.png in the folders res/drawable-*
Leave a Reply