Mobile Programming Lecture 9 Bound Services, Location, Sensors, IntentFilter
Agenda Bound Services Location Sensors Starting an Activity for a Result Understanding Implicit Intents
Bound Service When you create a Bound Service, you must provide an IBinder that provides the programming interface that clients can use to interact with the Service There are 3 ways that you can provide this interface: 1. Extending the Binder class 2. Using a Messenger 3. Using AIDL
Bound Service
Bound Service - 1 extending Binder This is the preferred technique when your service is merely a background worker for your own application The only reason you would not create your interface this way is because your service is used by other applications or across separate processes
Bound Service - 1 extending Binder Here's how to set it up 1. In your service, create an instance of Binder that returns the current Service instance, which has public methods the client can call 2. Return this instance of Binder from the onbind() callback method 3. In the client, receive the Binder from the onserviceconnected() callback method and make calls to the bound service using the methods provided
Bound Service - 1 extending Binder See BoundServiceBinder Example ServiceConnection class monitors the connection between the client and the Service When a Service is bound, the binder returned is returned to the onserviceconnected() method of ServiceConnection
Bound Service - 2 using Messenger If you need your interface to work across different processes, you can create an interface for the service with a Messenger The service defines a Handler that responds to different types of Message objects Additionally, the client can define a Messenger of it's own so the service can send messages back. This is the simplest way to perform interprocess communication (IPC), because the Messenger queues all requests into a single thread so that you don't have to design your service to be thread-safe
Bound Service - 2 using Messenger Notice that the handlemessage() method in the Handler is where the service receives the incoming Message and decides what to do, based on the what member.
Bound Service - 2 using Messenger See BoundServiceMessenger Example
Bound Service - 3 using the AIDL Using AIDL is way too specific Has benefits over extending Binder Supports parcelable objects Can be accessed from different applications (API) Handles multithreading We won't cover this, but you can read more about it here
Location Providers To obtain user location, you can use GPS Most accurate But Consumes battery power fast Takes a while to determine location Network Location Provider
Location - LocationManager Requesting Location Updates To get the user s location, you need to use the LocationManager, which is a system service This returns a Location object, which can tell you Latitude Longitude Distance between two locations (comparing to another Location object) Accuracy of the Location in meters Direction of travel in degrees Speed of travel in meters per second The Location, however, does not give you any human readable address such as street name, state, or country
Location - Geocoder and Address Requesting Location Updates You can use the Location object to obtain a human-readable address by using a Geocoder Geocoder can give you a list of addresses (since it may not always be sure because of accuracy issues) Returns a List of Address objects, i.e. List<Address> Street name City State Country Zip Code
Location - Last Known Location Since GPS and Wifi location are not quite instantaneous, you can get the last known location until one of them becomes available
Location - Last Known Location final LocationManager lm = (LocationManager) getsystemservice(context.location_service); getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { Location lastloc = lm.getlastknownlocation( LocationManager.NETWORK_PROVIDER); Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), lastloc.getlongitude(), 1); ); if (addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location final LocationManager lm = (LocationManager) getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { Location lastloc = lm.getlastknownlocation( getsystemservice(context.location_service); LocationManager.NETWORK_PROVIDER); Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), Similar to getting the system service for the DownloadManager lastloc.getlongitude(), 1); ); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location final LocationManager lm = (LocationManager) getsystemservice(context.location_service); getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { Location lastloc = lm.getlastknownlocation( LocationManager.NETWORK_PROVIDER); Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), What was the last known location? lastloc.getlongitude(), 1); ); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location final LocationManager lm = (LocationManager) getsystemservice(context.location_service); getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { We need to use @Override Geocoder to transform public void onclick(view v) longitude { and latitude to Location lastloc = lm.getlastknownlocation( an address LocationManager.NETWORK_PROVIDER); Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), lastloc.getlongitude(), 1); ); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location final LocationManager lm = (LocationManager) getsystemservice(context.location_service); getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { We will store said Location lastloc = lm.getlastknownlocation( address here LocationManager.NETWORK_PROVIDER); Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), lastloc.getlongitude(), 1); ); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location final LocationManager lm = (LocationManager) getsystemservice(context.location_service); getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { Let's get a List of Location lastloc = lm.getlastknownlocation( Addresses (although there may be only LocationManager.NETWORK_PROVIDER); 1 Geocoder geo = new Geocoder(getApplicationContext()); sometimes) List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), lastloc.getlongitude(), 1); ); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location final LocationManager lm = (LocationManager) getsystemservice(context.location_service); getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { Location lastloc = lm.getlastknownlocation( Pass LocationManager.NETWORK_PROVIDER); the latitude... Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), lastloc.getlongitude(), 1); ); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location final LocationManager lm = (LocationManager) getsystemservice(context.location_service); getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { Location lastloc = lm.getlastknownlocation( LocationManager.NETWORK_PROVIDER); Geocoder geo = new Geocoder(getApplicationContext()); the longitude... List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), lastloc.getlongitude(), 1); ); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location final LocationManager lm = (LocationManager) getsystemservice(context.location_service); getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { Location lastloc = lm.getlastknownlocation( LocationManager.NETWORK_PROVIDER); and the max number of Geocoder geo = new Geocoder(getApplicationContext()); addresses that you want to be returned List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), lastloc.getlongitude(), 1); ); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location final LocationManager lm = (LocationManager) getsystemservice(context.location_service); getbutton = (Button) findviewbyid(r.id.button1); tv = (TextView) findviewbyid(r.id.textview1); getbutton.setonclicklistener(new View.OnClickListener() { @Override public void onclick(view v) { Location lastloc = lm.getlastknownlocation( LocationManager.NETWORK_PROVIDER); Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses; addresses = geo.getfromlocation(lastloc.getlatitude(), Get the first line of the lastloc.getlongitude(), 1); first address in the list ); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0));
Location - Last Known Location See LastKnownLocation Example
Location - Location Updates Requesting Location Updates To get actual location updates periodically, you should use a LocationListener At some point, you should stop requesting location updates, possibly when Activity loses focus You no longer need the location
Location - Location Updates final LocationManager lm = (LocationManager) getsystemservice( LOCATION_SERVICE); final LocationListener ll = new LocationListener() { @Override public void onstatuschanged(string provider, int status, Bundle extras) { @Override public void onproviderenabled(string provider) { @Override public void onproviderdisabled(string provider) { @Override public void onlocationchanged(location location) { Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses = null; addresses = geo.getfromlocation(location.getlatitude(), location.getlongitude(), 1); if (addresses!= null) tv.settext(addresses.get(0).getaddressline(0)); ; lm.removeupdates( this);
Location - Location Updates final LocationManager lm = (LocationManager) getsystemservice(location_service); final LocationListener ll = new LocationListener() { @Override public void onstatuschanged(string provider, int status, Bundle extras) { @Override public void onproviderenabled(string provider) { @Override public void onproviderdisabled(string provider) { We need to register a LocationListener if we want to get updates on the location periodically @Override public void onlocationchanged(location location) { Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses = null; addresses = geo.getfromlocation(location.getlatitude(), location.getlongitude(), 1); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0)); ; lm.removeupdates(this);
Location - Location Updates final LocationManager lm = (LocationManager) getsystemservice(location_service); final LocationListener ll = new LocationListener() { @Override public void onstatuschanged(string provider, int status, Bundle extras) { @Override public void onproviderenabled(string provider) { @Override public void onproviderdisabled(string provider) { @Override public void onlocationchanged(location location) { Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses = null; addresses = geo.getfromlocation(location.getlatitude(), if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0)); We're forced to override these methods, although we don't use them location.getlongitude(), 1); ; lm.removeupdates(this);
Location - Location Updates final LocationManager lm = (LocationManager) getsystemservice(location_service); final LocationListener ll = new LocationListener() { @Override public void onstatuschanged(string provider, int status, Bundle extras) { @Override public void onproviderenabled(string provider) { @Override public void onproviderdisabled(string provider) { @Override public void onlocationchanged(location location) { Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses = null; addresses = geo.getfromlocation(location.getlatitude(), if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0)); In this callback method is where you code your response to a location change location.getlongitude(), 1); ; lm.removeupdates(this);
Location - Location Updates final LocationManager lm = (LocationManager) getsystemservice(location_service); final LocationListener ll = new LocationListener() { @Override public void onstatuschanged(string provider, int status, Bundle extras) { @Override public void onproviderenabled(string provider) { @Override public void onproviderdisabled(string provider) { Nothing new here... @Override public void onlocationchanged(location location) { Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses = null; addresses = geo.getfromlocation(location.getlatitude(), location.getlongitude(), 1); if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0)); ; lm.removeupdates(this);
Location - Location Updates final LocationManager lm = (LocationManager) getsystemservice(location_service); final LocationListener ll = new LocationListener() { @Override public void onstatuschanged(string provider, int status, Bundle extras) { @Override public void onproviderenabled(string provider) { @Override public void onproviderdisabled(string provider) { ; @Override public void onlocationchanged(location location) { Geocoder geo = new Geocoder(getApplicationContext()); List<Address> addresses = null; addresses = geo.getfromlocation(location.getlatitude(), if(addresses!= null) tv.settext(addresses.get(0).getaddressline(0)); lm.removeupdates(this); Let's save battery life and stop listening for updates, although you may choose to stop listening for updates at some other point if you want to location.getlongitude(), 1);
Location - Location Updates See LocationManager Example
Location - Proximity Alert Sometimes instead of retrieving the current location, you may want to know when the user arrives at a certain location For example, in turn-by-turn directions, you may want to know when the user is close to the next turning point You can use the addproximityalert() method of the LocationManager to accomplish this This registers a PendingIntent
Location - Proximity Alert @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); LocationManager lm = (LocationManager) getsystemservice(location_service); PendingIntent pi = creatependingresult(1, new Intent(), 0); Location loc = lm.getlastknownlocation(locationmanager.gps_provider); lm.addproximityalert(loc.getlatitude(), loc.getlongitude(), 10, -1, pi); Toast.makeText(this, "You're on the way", Toast.LENGTH_SHORT).show(); @Override public void onactivityresult(int reqcode, int resultcode, Intent data) { Toast.makeText(this, "You have arrived", Toast.LENGTH_SHORT).show();
Location - Proximity Alert @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); LocationManager lm = (LocationManager) getsystemservice(location_service); PendingIntent pi = creatependingresult(1, new Intent(), 0); We've used PendingIntent this way before when we talked about Services Location loc = lm.getlastknownlocation(locationmanager.gps_provider); lm.addproximityalert(loc.getlatitude(), loc.getlongitude(), 10, -1, pi); Toast.makeText(this, "You're on the way", Toast.LENGTH_SHORT).show(); @Override public void onactivityresult(int reqcode, int resultcode, Intent data) { Toast.makeText(this, "You have arrived", Toast.LENGTH_SHORT).show();
Location - Proximity Alert @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); LocationManager lm = (LocationManager) getsystemservice(location_service); Let's see how long it takes for the system to tell PendingIntent pi = creatependingresult(1, new Intent(), 0); us when we get back to our last known location Location loc = lm.getlastknownlocation(locationmanager.gps_provider); lm.addproximityalert(loc.getlatitude(), loc.getlongitude(), 10, -1, pi); Toast.makeText(this, "You're on the way", Toast.LENGTH_SHORT).show(); @Override public void onactivityresult(int reqcode, int resultcode, Intent data) { Toast.makeText(this, "You have arrived", Toast.LENGTH_SHORT).show();
Location - Proximity Alert @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); LocationManager lm = (LocationManager) getsystemservice(location_service); PendingIntent pi = creatependingresult(1, new Intent(), 0); Location loc = lm.getlastknownlocation(locationmanager.gps_provider); lm.addproximityalert(loc.getlatitude(), loc.getlongitude(), 10, -1, pi); Toast.makeText(this, "You're on the way", Toast.LENGTH_SHORT).show(); Whenever we get to that location, this callback method will handle the event @Override public void onactivityresult(int reqcode, int resultcode, Intent data) { Toast.makeText(this, "You have arrived", Toast.LENGTH_SHORT).show();
Location - Proximity Alert See LocationProximityAlert Example
Location - Permissions In order to receive location updates from NETWORK_PROVIDER or GPS_PROVIDER, you must request user permission by declaring one or both of the following permissions ACCESS_COARSE_LOCATION (Wifi location) ACCESS_FINE_LOCATION (GPS location)
Location - Mock Location You can test your location-based features by mocking location data in the Emulator http://developer.android.com/guide/topics/location/obtai ning-user-location.html#mockdata The Emulator uses the GPS provider Found under the Emulator Control View in Android Device Monitor, under the Emulator Control view You can open Android Device Monitor from Android Studio Tools > Android > Android Device Monitor
Sensor Accelerometer Gyroscope Light Orientation (DEPRECATED!) Proximity Pressure and more See SensorList Example
SensorManager SensorManager lets you access the device's sensors. Get an instance of this class by calling Context.getSystemService() with the argument SENSOR_SERVICE. Always make sure to disable sensors you don't need, especially when your activity is paused Failing to do so can drain the battery in just a few hours The system will not disable sensors automatically when the screen turns off.
SensorEvent The values for each sensor may change at some point Set up an Event Listener to take action when these change These values can be retrieved from a float values[] array, regardless of the type of sensor
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener { SensorManager msensormanager; Sensor mproximity; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout. main); msensormanager = (SensorManager)getSystemService( SENSOR_SERVICE); mproximity = msensormanager.getdefaultsensor(sensor. TYPE_PROXIMITY);...
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener { SensorManager Because we want msensormanager; to know when there's a SensorEvent, Sensor when values mproximity; of the Sensor change public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); msensormanager = (SensorManager)getSystemService(SENSOR_SERVICE); mproximity = msensormanager.getdefaultsensor(sensor.type_proximity);...
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener { SensorManager msensormanager; Sensor mproximity; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); Similar to how we got the Location service msensormanager = (SensorManager)getSystemService(SENSOR_SERVICE); mproximity = msensormanager.getdefaultsensor(sensor.type_proximity);...
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener { SensorManager msensormanager; Sensor mproximity; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); msensormanager = (SensorManager)getSystemService(SENSOR_SERVICE); mproximity = msensormanager.getdefaultsensor(sensor.type_proximity); Let's get a Sensor...
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener { SensorManager msensormanager; Sensor mproximity; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main);... msensormanager = (SensorManager)getSystemService(SENSOR_SERVICE); mproximity = msensormanager.getdefaultsensor( Sensor.TYPE_PROXIMITY); The Proximity Sensor specifically
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener { SensorManager msensormanager; Sensor mproximity; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); msensormanager = (SensorManager)getSystemService(SENSOR_SERVICE); mproximity = msensormanager.getdefaultsensor(sensor.type_proximity);... The rest of the code for this class on the next slide
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... oncreate() is here somewhere, on the protected previous void onresume() page { super.onresume(); msensormanager.registerlistener(this, mproximity, SensorManager.SENSOR_DELAY_NORMAL); protected void onpause() { super.onpause(); msensormanager.unregisterlistener(this); public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show();
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mproximity, SensorManager.SENSOR_DELAY_NORMAL); protected void onpause() { Note that this is onresume() super.onpause(); msensormanager.unregisterlistener(this); public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show();
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mproximity, We only want to listen when the Activity is visible in this case, so protected we do void this onpause() in onresume() { super.onpause(); msensormanager.unregisterlistener(this); SensorManager.SENSOR_DELAY_NORMAL); public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show();
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mproximity, SensorManager.SENSOR_DELAY_NORMAL); We pass a Context... protected void onpause() { super.onpause(); msensormanager.unregisterlistener(this); public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show();
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mproximity, SensorManager.SENSOR_DELAY_NORMAL); a Sensor... protected void onpause() { super.onpause(); msensormanager.unregisterlistener(this); public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show();
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mproximity, protected void onpause() { super.onpause(); msensormanager.unregisterlistener(this); SensorManager.SENSOR_DELAY_NORMAL); and the rate we want sensor events to be delivered public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show();
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mproximity, SensorManager.SENSOR_DELAY_NORMAL); protected void onpause() { super.onpause(); msensormanager.unregisterlistener(this); in onpause(), we want to stop listening for updates, preserving battery life public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show();
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mproximity, SensorManager.SENSOR_DELAY_NORMAL); protected void onpause() { super.onpause(); msensormanager.unregisterlistener(this); This is where we take action when there is a change in Sensor values public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show();
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mproximity, SensorManager.SENSOR_DELAY_NORMAL); protected void onpause() { super.onpause(); msensormanager.unregisterlistener(this); public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show(); event.values[] array has important data about the sensor event
SensorEvent public class SensorExampleActivity extends Activity implements SensorEventListener {... protected void onresume() { super.onresume(); msensormanager.registerlistener(this, mproximity, SensorManager.SENSOR_DELAY_NORMAL); protected void onpause() { super.onpause(); msensormanager.unregisterlistener(this); Refer to this page for details for each type of Sensor public void onsensorchanged(sensorevent event) { Toast.makeText(this, "Proximity = " + event.values[0], Toast.LENGTH_SHORT).show();
SensorEvent See: ProximitySensor Example LightSensor Example The code change between these two examples is very small
Using Sensors to Create a NUI NUI = Natural User Interface Human Computer Interaction is moving further and further away from the mouse and keyboard. Being replaced by gestures on the device, air gestures, speech recognition, and kinetics. There are typically two phases to gesture recognition Data Gathering Gesture Detection
Touch Using Gesture Detection you can register to listen for touch events on the device. Long Press Double Tap Fling Pinch Multiple Finger gestures
Telepathy Can think of this gesture as an air gesture Passing your hand over the device without touching the screen Might think that this would require a front facing camera to process this gesture.. This would be an option but there is an easier way Use the Light Sensor to recognize the gesture And the Proximity Sensor to validate
Kinetics This is the term for gestures using the device itself Taking advantage of the accelerometer, gravity sensor, gyroscope, compass, etc ICS - Huge improvement for gyroscope Things to look out for Power consumption Sampling Rate Varies by phone and is in nanoseconds NOT milliseconds Also, it is not synced with system time! Event comes with timestamp There will always be static and random variation Accelerometer data
Microphone Using Speech is a no brainer for NUI http://developer.android.com/reference/android/spee ch/recognizerintent.html A more technical way of using the microphone requires signal processing Way, way, way outside the scope of this class
Making Sense of the Data Thresholds Time Check peaks Filter peaks that are too close Based on count Combine with sensor data to get heart rate, for example Statistics are your friend Since sensors spit out messy and noisy data Mean, median, mode, range, etc
Starting Activities & Getting Results If you created two Activities A and B, you can start B from A, and have B return some result to A instead of startactivity(intent) call startactivityforresult(intent, int)
Starting Activities & Getting Results private int MY_CODE = 29; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); public void startsecondactivity(view v) { Intent intent = new Intent(A.this, B.class); startactivityforresult(intent, MY_CODE);
Starting Activities & Getting Results private int MY_CODE = 29; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); This code is for Activity A public void startsecondactivity(view v) { Intent intent = new Intent(A.this, B.class); startactivityforresult(intent, MY_CODE);
Starting Activities & Getting Results private int MY_CODE = 29; Some number that you want to use to identify your request. #29 is nothing special here. @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); public void startsecondactivity(view v) { Intent intent = new Intent(A.this, B.class); startactivityforresult(intent, MY_CODE);
Starting Activities & Getting Results private int MY_CODE = 29; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); public void startsecondactivity(view v) { Intent intent = new Intent(A.this, B.class); startactivityforresult(intent, MY_CODE); I added a button to the XML and set the android:onclick attribute to this method
Starting Activities & Getting Results private int MY_CODE = 29; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); We have seen this before public void startsecondactivity(view v) { Intent intent = new Intent(A.this, B.class); startactivityforresult(intent, MY_CODE);
Starting Activities & Getting Results private int MY_CODE = 29; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); public void startsecondactivity(view v) { Intent intent = new Intent(A.this, B.class); startactivityforresult(intent, MY_CODE); Instead of startactivity(intent), we call startactivityforresult and give it the intent along with our "special" request code.
Starting Activities & Getting Results protected void onactivityresult(int requestcode, { int resultcode, Intent data) if(requestcode == MY_CODE) { if(resultcode == RESULT_OK) { // result is OK, add code here We also need to add this method to Activity A, to react to when the result has been returned from Activity B.
Starting Activities & Getting Results public class B extends Activity { @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.second); public void finishme(view v) { setresult(activity.result_ok, null); finish();
Starting Activities & Getting Results public class B extends Activity { @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.second); public void finishme(view v) { This code is for Activity B setresult(activity.result_ok, null); finish();
Starting Activities & Getting Results public class B extends Activity { @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.second); public void finishme(view v) { setresult(activity.result_ok, null); finish(); Assuming there's a Button with android:onclick="finishme"
Starting Activities & Getting Results public class B extends Activity { @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.second); public void finishme(view v) { setresult(activity.result_ok, null); finish(); Set the result of this Activity to OK. The second argument is an Intent, but we'll go in to this another time.
Starting Activities & Getting Results public class B extends Activity { @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.second); public void finishme(view v) { setresult(activity.result_ok, null); finish(); Finish this Activity B, which will lead to ondestroy() being called, and Activity A becoming active. onactivityresult() in A will then be called.
Starting Activities & Getting Results See StartActivityForResult Example
Starting Activities & Getting Results As another example, let's call upon an existing Android Activity for a result
Starting Activities & Getting Results static final int PICK_REQUEST = 1337; Here's our request code again @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); public void pickcontact(view v) { Intent intent = new Intent(Intent.ACTION_PICK, Phone.CONTENT_URI); startactivityforresult(intent, PICK_REQUEST); protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == PICK_REQUEST) { if (resultcode == RESULT_OK) { /* result is OK! */
Starting Activities & Getting Results static final int PICK_REQUEST = 1337; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); Tied to a Button with public void pickcontact(view v) { android:onclick="pickcontact" Intent intent = new Intent(Intent.ACTION_PICK, Phone.CONTENT_URI); startactivityforresult(intent, PICK_REQUEST); protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == PICK_REQUEST) { if (resultcode == RESULT_OK) { /* result is OK! */
Starting Activities & Getting Results static final int PICK_REQUEST = 1337; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); We use a different constructor for the Intent this time public void pickcontact(view v) { Intent intent = new Intent(Intent.ACTION_PICK, Phone.CONTENT_URI); startactivityforresult(intent, PICK_REQUEST); protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == PICK_REQUEST) { if (resultcode == RESULT_OK) { /* result is OK! */
Starting Activities & Getting Results static final int PICK_REQUEST = 1337; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); These two arguments must mean something together, they don't always do! public void pickcontact(view v) { Intent intent = new Intent(Intent.ACTION_PICK, Phone.CONTENT_URI); startactivityforresult(intent, PICK_REQUEST); protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == PICK_REQUEST) { if (resultcode == RESULT_OK) { /* result is OK! */
Starting Activities & Getting Results static final int PICK_REQUEST = 1337; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); There should be an Activity that recognizes this Intent public void pickcontact(view v) { Intent intent = new Intent(Intent.ACTION_PICK, Phone.CONTENT_URI); startactivityforresult(intent, PICK_REQUEST); protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == PICK_REQUEST) { if (resultcode == RESULT_OK) { /* result is OK! */
Starting Activities & Getting Results static final int PICK_REQUEST = 1337; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); If none exists, you will probably get Force Close public void pickcontact(view v) { Intent intent = new Intent(Intent.ACTION_PICK, Phone.CONTENT_URI); startactivityforresult(intent, PICK_REQUEST); protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == PICK_REQUEST) { if (resultcode == RESULT_OK) { /* result is OK! */
Starting Activities & Getting Results static final int PICK_REQUEST = 1337; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); public void pickcontact(view v) { Nothing new here Intent intent = new Intent(Intent.ACTION_PICK, Phone.CONTENT_URI); startactivityforresult(intent, PICK_REQUEST); protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == PICK_REQUEST) { if (resultcode == RESULT_OK) { /* result is OK! */
Starting Activities & Getting Results static final int PICK_REQUEST = 1337; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); public void pickcontact(view v) { That starts Activity B. When Intent intent = new Intent(Intent.ACTION_PICK, Phone.CONTENT_URI); Activity B has returned, the startactivityforresult(intent, result PICK_REQUEST); will be returned to this callback function protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == PICK_REQUEST) { if (resultcode == RESULT_OK) { /* result is OK! */
Starting Activities & Getting Results See PickContacts Example
Understanding Implicit Intents Implicit Intents Specify the action that should be performed and optionally the URI which should be used in conjunction with the action Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse( http://www.google.com )); The Android system searches for all the components that are registered to handle this specific action If the system only finds one component then it will launch that automatically Else it will show a dialog that will give the user the option of selecting the one they prefer If none is found, you may get an Exception
Understanding Implicit Intents How do you know which Intent Action to specify for a given Uri?
Understanding Implicit Intents There are three rules, all of which must be true for a given activity to be eligible for a given intent 1. The activity must support the specified action 2. The activity must support the stated MIME type (if supplied) 3. The activity must support all of the categories named in the intent The upshot is that you want to make your intents specific enough to find the right receiver(s), and no more specific than that.
Understanding Implicit Intents Let's take a look at what happens when when the Home key is pressed...
Understanding Implicit Intents Open LogCat Click the + button to add a new filter Enter the following Filter Name: ActivityManager Log Tag: ActivityManager Now press the Home key on your device For the Tag Column, look for ActivityManager For the Text Column, look for anything beginning with "Starting: Intent..." The last one should be the Intent that was used to launch the home screen Mouseover that row, and you should see values for the following act, which is the action - android.intent.action.main cat, which is the category - android.intent.category.home in this case, there is no data, but sometimes there is Note the action and category
Understanding Implicit Intents Can we create our own Home Screen app? Create a new project Open AndroidManifest.xml Add a new intent-filter to your Activity The action should match the one you found in LogCat So should the category In addition, add the DEFAULT category <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.home" /> <category android:name="android.intent.category.default" /> </intent-filter>
Understanding Implicit Intents Now press the Home key... For a nicer effect, make your Activity full-screen by adding this to the <activity> tag in the manifest file android:theme="@android:style/theme.notitlebar.fullscreen" JUST DO NOT TO MAKE YOUR NEW HOME SCREEN DEFAULT IF YOU ADD THE FULLSCREEN FEATURE
Understanding Implicit Intents See HomeScreen Example
Understanding Implicit Intents It's not too difficult to figure out the Java code for the same Intent: <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.home" /> <category android:name="android.intent.category.default" /> </intent-filter> or IntentFilter myfilter = new IntentFilter(Intent.ACTION_MAIN); myfilter.addcategory(intent.category_home);
Understanding Implicit Intents If you make your Intent Filters Too vague Too specific It won't match what you expect it to. Try to make your Intent Filters precise!
Understanding Implicit Intents Now that you know a little bit about Intents, try to figure this out. If you developed a Music Player, how would you go about allowing the user to choose your Music Player after clicking on a music file on his or her phone?
References The Busy Coder's Guide to Android Development - Mark Murphy Android Developers The Mobile Lab at Florida State University