Always On, Always Connected Week 5 - Mobile Media

Drawing

If you would like to programmatically create graphics or UI elements, you can extend the View class.

Example:
View:
package com.mobvcasting.simpledrawexample;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class DrawingView extends View {
    
	public DrawingView(Context context) {
        super(context);
    }
	
	/*  This and the next constructor are required for creating the view via XML */
	public DrawingView(Context context, AttributeSet attrs) {
		super(context,attrs);
	}
	
	public DrawingView(Context context, AttributeSet attrs, int defStyle) {
		super(context,attrs,defStyle);
	}
    
    /* Override this method to implement your drawing routines */
	@Override
    protected void onDraw(Canvas canvas) {
		Paint p = new Paint();
		
		p.setColor(Color.BLUE);
		//p.setARGB(a, r, g, b)

		int width = getWidth();
		int height = getHeight();

		canvas.drawLine(0, 0, width, height, p);
  		
		canvas.drawText("HELLO", 5, 10, p);
	}		
}		
		

Full Project in Git Repo: https://github.com/vanevery/SimpleDrawingExample

Touch

Of course, we could make a View that allowed you to effectively draw on it using Touch events.

Example:
View:
package com.mobvcasting.fingerdrawingexample;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

// We are extending ImageView so that we can have a persistent Bitmap and the means to display it
public class DrawingView extends ImageView implements OnTouchListener {
    
	public final static String LOGTAG = "DrawingView";
	
	Bitmap bitmap;
	Paint paint;
	Canvas canvas;

	float downX = 0;
	float downY = 0;
	float upX = 0;
	float upY = 0;
	
	public DrawingView(Context context) {
        super(context);
    }
	
	public DrawingView(Context context, AttributeSet attrs) {
		super(context,attrs);
	}
	
	public DrawingView(Context context, AttributeSet attrs, int defStyle) {
		super(context,attrs,defStyle);
	}
	
	public void init() {
		
        bitmap = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_8888);
        canvas = new Canvas(bitmap);
        paint = new Paint();
        paint.setColor(Color.RED);
        this.setImageBitmap(bitmap);
		this.setOnTouchListener(this);
	}

	@Override 
	protected void onSizeChanged (int w, int h, int oldw, int oldh)
	{
		Log.v(LOGTAG,"onSizeChanged:" + w + " " + h + " " + oldw + " " + oldh);
		if (w != 0 && h != 0) {
			init();
		}
	}
	
	@Override
	public boolean onTouch(View v, MotionEvent motionEvent) {
		
		if (bitmap != null) 
		{
			Log.v(LOGTAG,"onTouch, bitmap isn't null");
			
			int action = motionEvent.getAction();			
			switch (action) {
				case MotionEvent.ACTION_DOWN:
					downX = motionEvent.getX();
					downY = motionEvent.getY();
					break;
				case MotionEvent.ACTION_MOVE:
					break;
				case MotionEvent.ACTION_UP:
					upX = motionEvent.getX();
					upY = motionEvent.getY();
					canvas.drawLine(downX, downY, upX, upY, paint);
					invalidate();
					break;
				case MotionEvent.ACTION_CANCEL:
					break;	
				default: 
					break;
			}			
		} 
		return true;
	}	
}        
		

Full Example Git Repo: https://github.com/vanevery/FingerDrawingExample.git

Accelerometer

Example:
package com.mobvcasting.accelerometerexample;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;

public class AccelerometerExampleActivity extends Activity implements SensorEventListener {

	private SensorManager sensorManager;
	private Sensor accelerometerSensor;

	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
		accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    }
	
	@Override
	protected void onResume() {
		super.onResume();
		sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL);
	}	

	@Override 
	protected void onPause() {
		super.onPause();
    	sensorManager.unregisterListener(this);
    }
	
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
	}

	public void onSensorChanged(SensorEvent event) {
		Log.v("Accel","X: " + event.values[0]);
		Log.v("Accel","Y: " + event.values[1]);
		Log.v("Accel","Z: " + event.values[2]);
	}
}
		
Full Example Git Repo: https://github.com/vanevery/AccelerometerExample

Compass

Example:
/*
 * Compass Example with help from:
 * http://www.codingforandroid.com/2011/01/using-orientation-sensors-simple.html
 */

package com.mobvcasting.compass;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.View;

public class CompasExample extends Activity implements SensorEventListener {

	static final String LOGTAG = "Compass";
	
	SensorManager sensorManager;
    SensorEventListener sensorListener;
    
    Sensor magnometerSensor;
    Sensor accelerometerSensor;
    
    AniView animationView;
    
    float[] accelerometerMatrix;
    float[] magnometerMatrix;
    
    float azimuth = 0.0f;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 
        
        AniView animationView = new AniView(this);
        setContentView(animationView);

        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        magnometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
    }
    
    public void onResume() {
        super.onResume();
        
        sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(this, magnometerSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }
    
    public void onPause() {
    	super.onPause();
    	sensorManager.unregisterListener(this);
    }
    
    public void onSensorChanged(SensorEvent event) {
    	
    	if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) 
    	{
    		magnometerMatrix = event.values;
    	}
    	else if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) 
    	{
    		accelerometerMatrix = event.values;
    	}
    	
    	
    	if (magnometerMatrix != null && accelerometerMatrix != null) {
    		float R[] = new float[9];
    		float I[] = new float[9];
    		
    		//https://developer.android.com/reference/android/hardware/SensorManager.html
    		boolean rotationMatrixSuccess = SensorManager.getRotationMatrix(R, I, accelerometerMatrix, magnometerMatrix);
    	    
    		if (rotationMatrixSuccess) {
    	        float orientation[] = new float[3];
    	        SensorManager.getOrientation(R, orientation);
    	        azimuth = orientation[0]; // orientation contains: azimuth (around z axis), pitch (around y axis) and roll
    	    }    		
    	}
    	
    }

    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }

    class AniView extends View {

        public AniView(Context context) {
            super(context);
        }
        
    	@Override
        protected void onDraw(Canvas canvas) {
    		Paint p = new Paint();
    		p.setColor(Color.BLUE);

    		int width = getWidth();
    		int height = getHeight();
    		int centerx = width/2;
    		int centery = height/2;
    		canvas.drawLine(centerx, 0, centerx, height, p);
    		canvas.drawLine(0, centery, width, centery, p);
  
    		// Rotate the canvas with the azimuth      
    		canvas.rotate(-azimuth*360/(float)(2*Math.PI), centerx, centery);

    		p.setColor(Color.RED);
    		canvas.drawLine(centerx, -1000, centerx, +1000, p);
    		canvas.drawLine(-1000, centery, 1000, centery, p);
    		
    		canvas.drawText("N", centerx+5, centery-10, p);
    		canvas.drawText("S", centerx-10, centery+15, p);
  		
            invalidate();
    	}
    }
}        
		
Full Example Git Repo: https://github.com/vanevery/CompassExample

Location

Git Repo: https://github.com/vanevery/LocationTrackingExample Example: Requires Permissions:
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
package com.mobvcasting.locationtracking;

import android.app.Activity; 
import android.content.Context; 
import android.location.Location; 
import android.location.LocationListener; 
import android.location.LocationManager; 
import android.location.LocationProvider; 
import android.os.Bundle; 
import android.util.Log; 
import android.widget.TextView;

/*
To receive location updates from the LocationManager, we'll have our activity implement LocationListener.
*/

public class LocationTracking extends Activity implements LocationListener {

	LocationManager lm; 
	TextView tv;

	public void onCreate(Bundle savedInstanceState) { 
		super.onCreate(savedInstanceState); 
		setContentView(R.layout.main);
		tv = (TextView) this.findViewById(R.id.location); 
		
		/*
		We get an instance of LocationManager by using the getSystemService method available
		in Context, which Activity is a subclass of therefore it is available to us.
		*/
		lm = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

		/*
		LocationManager offers us the ability to specify that we want our LocationListener, in this case, our activity, to be notified of location-related changes. We register our activity as the LocationListener by passing it in as the last argument to the requestLocationUpdates method.
		The first argument in the method is the location provider that we would like to use. The two location providers available are specified as constants in the LocationManager class. The one we are using here, NETWORK_PROVIDER, utilizes network services such as cell tower location or WiFi access point location to determine location. The other one available is GPS_PROVIDER, which provides location information utilizing GPS (Global Positioning Satellites). NETWORK_PROVIDER is generally a much faster but potentially less accurate location lookup than GPS. GPS may take a significant amount of time to acquire signals from satellites and may not work at all indoors or in areas where the sky is not clearly visible (midtown Manhattan, for instance).

		The second argument is the minimum amount of time the system will wait between "location changed" notifications. It is specified as a long representing milliseconds. Here we are using 60,000 milliseconds or 1 minute.
		The third argument is the amount of distance that the location needs to have changed before a "location changed" notification is given. This is specified as a float representing meters. Here we are using 5 meters.
		 */

		lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 6000l, 5.0f, this);
		lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 6000l, 5.0f, this);
	}

	/*
	When using the LocationManager, particularly when using GPS as the provider, it may be prudent to stop the location updates when the application is no longer in the foreground. This will conserve battery power. To do so, we can override the normal onPause or onStop method in our activity and call the removeUpdates method on the LocationManager object.
	 */
	public void onPause() {
		super.onPause(); 
		lm.removeUpdates(this);
	}

	public void onResume() {
		super.onResume();
		lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 6000l, 5.0f, this);
		lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 6000l, 5.0f, this);
	}
	
	/*
	The onLocationChanged method will be called on the registered LocationListener and passed a Location object whenever the location has changed and the change is greater than the distance and time parameters specified in the requestLocationUpdates method.
	The Location object that is passed in has methods available for getting latitude (getLatitude), longitude (getLongitude), altitude (getAltitude), and many more, detailed in the documentation: http://developer.android.com/reference/android/location/Location.html.
	 */

	public void onLocationChanged(Location location) {
		Log.v("LOCATION", "Altitude " + location.getAltitude() + "Supported: " + location.hasAltitude());
		Log.v("LOCATION", "Bearing" + location.getBearing() + "Supported: " + location.hasBearing());
		tv.setText(location.getLatitude() + " " + location.getLongitude()); 
		Log.v("LOCATION", "onLocationChanged: lat=" + location.getLatitude() + ", lon=" + location.getLongitude());
	}

	/*
	The onProviderDisabled method within the registered LocationListener will get called should the provider that is being monitored be disabled by the user.
	*/
	public void onProviderDisabled(String provider) { 
		Log.v("LOCATION", "onProviderDisabled: " + provider);
	}

	/*
	The onProviderEnabled method within the registered LocationListener will get called
	should the provider that is being monitored be enabled by the user.
	*/
	public void onProviderEnabled(String provider) { 
		Log.v("LOCATION", "onProviderEnabled: " + provider);
	}

	/*
	Finally, the onStatusChanged method in the registered LocationListener will be called if the location provider's status changes. There are three constants in LocationProvider that can be tested against the status variable which can be usedto determine what the change that happened is. They are AVAILABLE, which will get called should the provider become available after a period of time being unavailable, TEMPORARILY_UNAVAILABLE, which is just as its name implies, the provider is temporarily unable to be used as it was
	unable to fetch the current location and lastly, OUT_OF_SERVICE, which means that the provider is unable to be used probably due to losing connectivity or signal.
	*/
	public void onStatusChanged(String provider, int status, Bundle extras) { 
		Log.v("LOCATION", "onStatusChanged: " + provider + " status:" + status); 
	
		if (status == LocationProvider.AVAILABLE) {
			Log.v("LOCATION","Provider Available"); 
		} else if (status == LocationProvider.TEMPORARILY_UNAVAILABLE) {
			Log.v("LOCATION","Provider Temporarily Unavailable"); 
		} else if (status == LocationProvider.OUT_OF_SERVICE) {
			Log.v("LOCATION","Provider Out of Service");
		}
	}
}      

	
------

Augmented Reality

Map