Chapter 15 Code Listings // Listing 15-1: Declaring a new permission //Listing 15-2: Enforcing a permission requirement for an Activity // Listing 15-3: Using a Wake Lock PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock"); wakeLock.acquire(); [ ... Do things requiring the CPU stay active ... ] wakeLock.release(); // Listing 15-4: Initializing Text to Speech boolean ttsIsInit = false; TextToSpeech tts = null; tts = new TextToSpeech(this, new OnInitListener() { public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { ttsIsInit = true; // TODO Speak! } } }); // Listing 15-5: Using Text to Speech private static int TTS_DATA_CHECK = 1; private TextToSpeech tts = null; private boolean ttsIsInit = false; private void initTextToSpeech() { Intent intent = new Intent(Engine.ACTION_CHECK_TTS_DATA); startActivityForResult(intent, TTS_DATA_CHECK); } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == TTS_DATA_CHECK) { if (resultCode == Engine.CHECK_VOICE_DATA_PASS) { tts = new TextToSpeech(this, new OnInitListener() { public void onInit(int status) { if (status == TextToSpeech.SUCCESS) { ttsIsInit = true; if (tts.isLanguageAvailable(Locale.UK) >= 0) tts.setLanguage(Locale.UK); tts.setPitch(0.8f); tts.setSpeechRate(1.1f); speak(); } } }); } else { Intent installVoice = new Intent(Engine.ACTION_INSTALL_TTS_DATA); startActivity(installIntent); } } } private void speak() { if (tts != null && ttsIsInit) { tts.speak("Hello, Android", TextToSpeech.QUEUE_ADD, null); } } @Override public void onDestroy() { if (tts != null) { tts.stop(); tts.shutdown(); } super.onDestroy(); } // Listing 15-6: Making the Quake class Parcelable package com.paad.earthquake; import java.util.Date; import android.location.Location; import android.os.Parcel; import android.os.Parcelable; public class Quake implements Parcelable { private Date date; private String details; private Location location; private double magnitude; private String link; public Date getDate() { return date; } public String getDetails() { return details; } public Location getLocation() { return location; } public double getMagnitude() { return magnitude; } public String getLink() { return link; } public Quake(Date _d, String _det, Location _loc, double _mag, String _link) { date = _d; details = _det; location = _loc; magnitude = _mag; link = _link; } @Override public String toString(){ SimpleDateFormat sdf = new SimpleDateFormat("HH.mm"); String dateString = sdf.format(date); return dateString + ":" + magnitude + " " + details; } private Quake(Parcel in) { date.setTime(in.readLong()); details = in.readString(); magnitude = in.readDouble(); Location location = new Location("generated"); location.setLatitude(in.readDouble()); location.setLongitude(in.readDouble()); link= in.readString(); } public void writeToParcel(Parcel out, int flags) { out.writeLong(date.getTime()); out.writeString(details); out.writeDouble(magnitude); out.writeDouble(location.getLatitude()); out.writeDouble(location.getLongitude()); out.writeString(link); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public Quake createFromParcel(Parcel in) { return new Quake(in); } public Quake[] newArray(int size) { return new Quake[size]; } }; public int describeContents() { return 0; } } // Listing 15-7: The Quake class AIDL definition package com.paad.earthquake; parcelable Quake; // Listing 15-8: An Earthquake Service AIDL Interface definition package com.paad.earthquake; import com.paad.earthquake.Quake; interface IEarthquakeService { List getEarthquakes(); void refreshEarthquakes(); } // Listing 15-9: Implementing the AIDL Interface definition within a Service IBinder myEarthquakeServiceStub = new IEarthquakeService.Stub() { public void refreshEarthquakes() throws RemoteException { EarthquakeService.this.refreshEarthquakes(); } public List getEarthquakes() throws RemoteException { ArrayList result = new ArrayList(); ContentResolver cr = EarthquakeService.this.getContentResolver(); Cursor c = cr.query(EarthquakeProvider.CONTENT_URI, null, null, null, null); if (c.moveToFirst()) do { Double lat = c.getDouble(EarthquakeProvider.LATITUDE_COLUMN); Double lng = c.getDouble(EarthquakeProvider.LONGITUDE_COLUMN); Location location = new Location("dummy"); location.setLatitude(lat); location.setLongitude(lng); String details = c.getString(EarthquakeProvider.DETAILS_COLUMN); String link = c.getString(EarthquakeProvider.LINK_COLUMN); double magnitude = c.getDouble(EarthquakeProvider.MAGNITUDE_COLUMN); long datems = c.getLong(EarthquakeProvider.DATE_COLUMN); Date date = new Date(datems); result.add(new Quake(date, details, location, magnitude, link)); } while(c.moveToNext()); return result; } }; // Listing 15-10: Exposing an AIDL Interface implementation to Service clients @Override public IBinder onBind(Intent intent) { return myEarthquakeServiceStub; } // Listing 15-11: Using an IPC Service method IEarthquakeService earthquakeService = null; private void bindService() { bindService(new Intent(IEarthquakeService.class.getName()), serviceConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection serviceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { earthquakeService = IEarthquakeService.Stub.asInterface(service); } public void onServiceDisconnected(ComponentName className) { earthquakeService = null; } }; // Listing 15-12: Creating a tweened animation in code // Create the AnimationSet AnimationSet myAnimation = new AnimationSet(true); // Create a rotate animation. RotateAnimation rotate = new RotateAnimation(0, 360, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); rotate.setFillAfter(true); rotate.setDuration(1000); // Create a scale animation ScaleAnimation scale = new ScaleAnimation(1, 0, 1, 0, ScaleAnimation.RELATIVE_TO_SELF, 0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f); scale.setFillAfter(true); scale.setDuration(500); scale.setStartOffset(500); // Create an alpha animation AlphaAnimation alpha = new AlphaAnimation(1, 0); scale.setFillAfter(true); scale.setDuration(500); scale.setStartOffset(500); // Add each animation to the set myAnimation.addAnimation(rotate); myAnimation.addAnimation(scale); myAnimation.addAnimation(alpha); // Listing 15-13: Defining a tweened animation in XML // Listing 15-14: Applying an Animation that loops continuously myAnimation.setRepeatMode(Animation.RESTART); myAnimation.setRepeatCount(Animation.INFINITE); myView.startAnimation(myAnimation); // Listing 15-15: Creating an Animation Listener myAnimation.setAnimationListener(new AnimationListener() { public void onAnimationEnd(Animation _animation) { // TODO Do something after animation is complete. } public void onAnimationRepeat(Animation _animation) { // TODO Do something when the animation repeats. } public void onAnimationStart(Animation _animation) { // TODO Do something when the animation starts. } }); // Listing 15-16: Creating a Layout Animation //res/anim/popin.xml //res/anim/popinlayout.xml // Listing 15-17: Applying a Layout Animation and Animation Listener aViewGroup.setLayoutAnimationListener(new AnimationListener() { public void onAnimationEnd(Animation _animation) { // TODO: Actions on animation complete. } public void onAnimationRepeat(Animation _animation) {} public void onAnimationStart(Animation _animation) {} }); aViewGroup.scheduleLayoutAnimation(); // Listing 15-18: Creating a frame-by-frame animation in XML // Applying an animation ImageView image = (ImageView)findViewById(R.id.my_animation_frame); image.setBackgroundResource(R.drawable.animated_rocket); AnimationDrawable animation = (AnimationDrawable)image.getBackground(); animation.start(); // Listing 15-19: Creating a Linear Gradient Shader int colorFrom = Color.BLACK; int colorTo = Color.WHITE; LinearGradient linearGradientShader = new LinearGradient(x1, y1, x2, y2, colorFrom, colorTo, TileMode.CLAMP); // Listing 15-20: Creating a Radial Gradient Shader int[] gradientColors = new int[3]; gradientColors[0] = Color.GREEN; gradientColors[1] = Color.YELLOW; gradientColors[2] = Color.RED; float[] gradientPositions = new float[3]; gradientPositions[0] = 0.0f; gradientPositions[1] = 0.5f; gradientPositions[2] = 1.0f; RadialGradient radialGradientShader = new RadialGradient(centerX, centerY, radius, gradientColors, gradientPositions, TileMode.CLAMP); // Listing 15-21: Applying an Emboss Mask Filter to a Paint // Set the direction of the light source float[] direction = new float[]{ 1, 1, 1 }; // Set the ambient light level float light = 0.4f; // Choose a level of specularity to apply float specular = 6; // Apply a level of blur to apply to the mask float blur = 3.5f; EmbossMaskFilter emboss = new EmbossMaskFilter(direction, light, specular, blur); // Apply the mask myPaint.setMaskFilter(emboss); // Listing 15-22: Handling Map View Overlay touch events @Override public boolean onTap(GeoPoint point, MapView map) { // Get the projection to convert to and from screen coordinates Projection projection = map.getProjection(); // Return true if we handled this onTap() return [ ... hit test passed ... ]; } // Listing 15-23: Surface View skeleton implementation import android.content.Context; import android.graphics.Canvas; import android.view.SurfaceHolder; import android.view.SurfaceView; public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; private MySurfaceViewThread mySurfaceViewThread; private boolean hasSurface; MySurfaceView(Context context) { super(context); init(); } private void init() { // Create a new SurfaceHolder and assign this class as its callback. holder = getHolder(); holder.addCallback(this); hasSurface = false; } public void resume() { // Create and start the graphics update thread. if (mySurfaceViewThread == null) { mySurfaceViewThread = new MySurfaceViewThread(); if (hasSurface == true) mySurfaceViewThread.start(); } } public void pause() { // Kill the graphics update thread if (mySurfaceViewThread != null) { mySurfaceViewThread.requestExitAndWait(); mySurfaceViewThread = null; } } public void surfaceCreated(SurfaceHolder holder) { hasSurface = true; if (mySurfaceViewThread != null) mySurfaceViewThread.start(); } public void surfaceDestroyed(SurfaceHolder holder) { hasSurface = false; pause(); } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (mySurfaceViewThread != null) mySurfaceViewThread.onWindowResize(w, h); } class MySurfaceViewThread extends Thread { private boolean done; MySurfaceViewThread() { super(); done = false; } @Override public void run() { SurfaceHolder surfaceHolder = holder; // Repeat the drawing loop until the thread is stopped. while (!done) { // Lock the surface and return the canvas to draw onto. Canvas canvas = surfaceHolder.lockCanvas(); // TODO: Draw on the canvas! // Unlock the canvas and render the current image. surfaceHolder.unlockCanvasAndPost(canvas); } } public void requestExitAndWait() { // Mark this thread as complete and combine into // the main application thread. done = true; try { join(); } catch (InterruptedException ex) { } } public void onWindowResize(int w, int h) { // Deal with a change in the available surface size. } } } // Listing 15-24: Handling single (or first) touch events @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case (MotionEvent.ACTION_DOWN) : // Touch screen pressed break; case (MotionEvent.ACTION_UP) : // Touch screen touch ended break; case (MotionEvent.ACTION_MOVE) : // Contact has moved across screen break; case (MotionEvent.ACTION_CANCEL) : // Touch event cancelled break; case (MotionEvent.ACTION_OUTSIDE) : // Movement has occurred outside the bounds // of the screen element being // monitored break; } return super.onTouchEvent(event); } // Listing 15-25: Handling multi-touch events @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); if (event.getPointerCount() > 1) { int actionPointerId = action & MotionEvent.ACTION_POINTER_ID_MASK; int actionEvent = action & MotionEvent.ACTION_MASK; // Do something with the pointer ID and event. } return super.onTouchEvent(event); } // Listing 15-26: Finding screen touch coordinates int xPos = -1; int yPos = -1; if (event.getPointerCount() > 1) { int actionPointerId = action & MotionEvent.ACTION_POINTER_ID_MASK; int actionEvent = action & MotionEvent.ACTION_MASK; int pointerIndex = findPointerIndex(actionPointerId); xPos = (int)event.getX(pointerIndex); yPos = (int)event.getY(pointerIndex); } else { // Single touch event. xPos = (int)event.getX(); yPos = (int)event.getY(); } // Listing 15-27: Finding historical touch event values int historySize = event.getHistorySize(); long time = event.getHistoricalEventTime(i); if (event.getPointerCount() > 1) { int actionPointerId = action & MotionEvent.ACTION_POINTER_ID_MASK; int pointerIndex = findPointerIndex(actionPointerId); for (int i = 0; i < historySize; i++) { float pressure = event.getHistoricalPressure(pointerIndex, i); float x = event.getHistoricalX(pointerIndex, i); float y = event.getHistoricalY(pointerIndex, i); float size = event.getHistoricalSize(pointerIndex, i); // TODO: Do something with each point } } else { for (int i = 0; i < historySize; i++) { float pressure = event.getHistoricalPressure(i); float x = event.getHistoricalX(i); float y = event.getHistoricalY(i); float size = event.getHistoricalSize(i); // TODO: Do something with each point } } // Listing 15-28: Handling touch screen movement events @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case (MotionEvent.ACTION_MOVE) { int historySize = event.getHistorySize(); for (int i = 0; i < historySize; i++) { float x = event.getHistoricalX(i); float y = event.getHistoricalY(i); processMovement(x, y); } float x = event.getX(); float y = event.getY(); processMovement(x, y); return true; } } return super.onTouchEvent(event); } private void processMovement(float _x, float _y) { // Todo: Do something on movement. } // Listing 15-29: Assigning an On Touch Listener to an existing View myView.setOnTouchListener(new OnTouchListener() { public boolean onTouch(View _view, MotionEvent _event) { // TODO Respond to motion events return false; } }); // Listing 15-30: Handling key press events @Override public boolean onKeyDown(int _keyCode, KeyEvent _event) { // Perform on key pressed handling, return true if handled return false; } @Override public boolean onKeyUp(int _keyCode, KeyEvent _event) { // Perform on key released handling, return true if handled return false; } // Listing 15-31: Implementing an On Key Listener within an Activity myView.setOnKeyListener(new OnKeyListener() { public boolean onKey(View v, int keyCode, KeyEvent event) { // TODO Process key press event, return true if handled return false; } }); // Listing 15-32: Using the On Trackball Event Listener @Override public boolean onTrackballEvent(MotionEvent _event) { float vertical = _event.getY(); float horizontal = _event.getX(); // TODO Process trackball movement. return false; }