1. package edu.ku.swingemu;
  2.  
  3. import java.io.BufferedOutputStream;
  4. import java.io.File;
  5. import java.io.FileNotFoundException;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8.  
  9. import android.app.Activity;
  10. import android.content.Context;
  11. import android.graphics.Bitmap;
  12. import android.graphics.Canvas;
  13. import android.graphics.Color;
  14. import android.graphics.Paint;
  15. import android.graphics.Path;
  16. import android.graphics.Rect;
  17. import android.graphics.RectF;
  18. import android.graphics.Bitmap.CompressFormat;
  19. import android.graphics.Paint.Align;
  20. import android.media.MediaScannerConnection;
  21. import android.os.Bundle;
  22. import android.os.Environment;
  23. import android.util.Log;
  24. import android.view.View;
  25. import android.view.ViewGroup;
  26.  
  27. /**
  28.  * Activity which expects the user to implement {@link #paint(Graphics)}
  29.  * Similar to a JApplet. This is intended to make Android graphics easier
  30.  * to use for someone familar with JApplets
  31.  *
  32.  * @author Nathan Schwermann
  33.  *
  34.  */
  35. public abstract class AndroidJApplet extends Activity {
  36.  
  37.     Graphics mGraphics;
  38.    
  39.     @Override
  40.     public void onCreate(Bundle savedInstanceState) {
  41.         super.onCreate(savedInstanceState);
  42.         //create a new Graphics object and set it as the content of the screen.
  43.         mGraphics = new Graphics(this);
  44.         mGraphics.setSwingEmuActivity(this);
  45.         mGraphics.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
  46.         setContentView(mGraphics);
  47.     }
  48.    
  49.     /**
  50.      * Saves the {@link Graphics} portion of the screen to a jpg<br>
  51.      * Stored in {@link Environment#DIRECTORY_PICTURES}<br>
  52.      * This will typically be /sdcard/pictures
  53.      * @param filename the name of the file to save
  54.      */
  55.     public void saveScreenToJPG(String filename){
  56.         mGraphics.saveScreenToJPG(filename);
  57.     }
  58.    
  59.     /**
  60.      * Make changes to the screen buffer, this method must be overridden by
  61.      * the user of this class but should never be directly called. Call {@link #repaint()} instead
  62.      * if you want to force the screen to be drawn.
  63.      * @param canvas
  64.      */
  65.     public abstract void paint(Graphics canvas);
  66.    
  67.     /**
  68.      * Forces the screen to be redrawn.
  69.      */
  70.     public final void repaint(){
  71.         mGraphics.invalidate();
  72.     }
  73.    
  74.     /**
  75.      * View to designed to mirror some of the java.awt.Graphics api
  76.      * @author Nathan Schwermann
  77.      */
  78.     public static class Graphics extends View{
  79.        
  80.         Paint mOutline, mFill;      
  81.         AndroidJApplet mActivity;
  82.         Bitmap mBitmap;
  83.         Canvas mCanvas;
  84.         int mbgColor;
  85.        
  86.         public Graphics(Context context) {
  87.             super(context);
  88.             //initialize our Paint objects and set the background to be white like a jApplet.
  89.             setBackgroundColor(Color.WHITE);
  90.             mOutline = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG);
  91.             mOutline.setColor(Color.BLACK);
  92.             mOutline.setStyle(Paint.Style.STROKE);
  93.             mOutline.setStrokeWidth(1f);
  94.             mOutline.setTextAlign(Align.LEFT);
  95.             mFill = new Paint(mOutline);
  96.             mFill.setStyle(Paint.Style.FILL);
  97.         }
  98.        
  99.         @Override
  100.         public void setBackgroundColor(int color) {
  101.             super.setBackgroundColor(color);
  102.             mbgColor = color;
  103.         }
  104.        
  105.         /**
  106.          * Sets the parent activity for callbacks in {@link #onDraw(Canvas)} so
  107.          * we can implement the same paint signature as an applet
  108.          * @param activity
  109.          */
  110.         final void setSwingEmuActivity(AndroidJApplet activity){
  111.             mActivity = activity;
  112.         }
  113.                
  114.         @Override
  115.         protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  116.             Log.d("test", "onSizeChagnged");
  117.             super.onSizeChanged(w, h, oldw, oldh);
  118.             //resize our offscreen canvas to match the screensize
  119.             mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  120.             mCanvas = new Canvas(mBitmap);
  121.         }
  122.        
  123.         @Override
  124.         protected void onDraw(Canvas canvas) {
  125.             super.onDraw(canvas);
  126.             if(mActivity == null) throw new NullPointerException("You must assign an AndroidJApplet to the Graphics object.");
  127.             //paint draws to our bitmap offscreen with the swing like api implemented by the student
  128.             mActivity.paint(this);
  129.             //commits the bitmap to our screen
  130.             canvas.drawBitmap(mBitmap, 0, 0, null);
  131.         }
  132.        
  133.         /**
  134.          * Clears the specified rectangle by filling it with the background color of the current drawing surface.
  135.          */
  136.         public void clearRect(int x, int y, int w, int h){
  137.             final int oldColor = mFill.getColor();
  138.             mFill.setColor(mbgColor);
  139.             fillRect(x, y, w, h);
  140.             mFill.setColor(oldColor);
  141.         }
  142.        
  143.         //Applet APIs
  144.         //All below APIs are made to have the same signature as
  145.         //their swing counterpart.
  146.        
  147.         /**
  148.          * Draws an oval with just an outline of the current color no fill
  149.          */
  150.         public void drawOval(int x, int y, int w, int h){
  151.             mCanvas.drawOval(new RectF(x, y, x + w, y + h), mOutline);
  152.         }
  153.        
  154.         /**
  155.          * Draws the outline of a circular or elliptical arc covering the specified rectangle.
  156.             A positive value indicates a counter-clockwise rotation while a negative value indicates a clockwise rotation. <br>
  157.             <b>note: this behavior is backwards compared to Android's normal drawArc API which draws in a clockwise rotation.</b>
  158.          */
  159.         public void drawArc(int x, int y, int w, int h, int start, int sweep){
  160.             mCanvas.drawArc(new RectF(x, y, x + w, y + h), start, -sweep, false, mOutline);
  161.         }
  162.        
  163.         /**
  164.          * Draws the text given by the specified string, using this graphics context's current font and color.
  165.          * The baseline of the leftmost character is at position (x, y) in this graphics context's coordinate system.
  166.          */
  167.         public void drawString(String text, int x, int y){
  168.             mCanvas.drawText(text, x, y, mOutline);
  169.         }
  170.        
  171.         /**
  172.          * Draws a line, using the current color, between the points (x1, y1) and (x2, y2) in this graphics context's coordinate system.
  173.          */
  174.         public void drawLine(int x1, int y1, int x2, int y2){
  175.             final Path p = new Path();
  176.             p.moveTo(x1, y1);
  177.             p.lineTo(x2, y2);
  178.             mCanvas.drawPath(p, mOutline);
  179.         }
  180.  
  181.         /**
  182.          * Draws the outline of the specified rectangle.
  183.          * The left and right edges of the rectangle are at x and x + width.
  184.          * The top and bottom edges are at y and y + height.
  185.          * The rectangle is drawn using the graphics context's current color.
  186.          */
  187.         public void drawRect(int x, int y, int width, int height){
  188.             mCanvas.drawRect(new Rect(x, y, x+width, y+height), mOutline);
  189.         }
  190.        
  191.         /**
  192.          * Draws an outlined round-cornered rectangle using this graphics context's current color.
  193.          * The left and right edges of the rectangle are at x and x + width, respectively.
  194.          * The top and bottom edges of the rectangle are at y and y + height.
  195.          */
  196.         public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight){
  197.             mCanvas.drawRoundRect(new RectF(x, y, x+width, y+height), arcWidth, arcHeight, mOutline);
  198.         }
  199.        
  200.         /**
  201.          * Draws an oval and fills it in with the current color
  202.          */
  203.         public void fillOval(int x, int y, int w, int h){
  204.             mCanvas.drawOval(new RectF(x, y, x + w, y + h), mFill);
  205.         }
  206.        
  207.         /**
  208.          * Fills the specified rectangle. The left and right edges of the rectangle are at x and x + width.
  209.          * The top and bottom edges are at y and y + height.
  210.          * The resulting rectangle covers an area width pixels wide by height pixels tall.
  211.          * The rectangle is filled using the graphics context's current color.
  212.          */
  213.         public void fillRect(int x, int y, int width, int height){
  214.             mCanvas.drawRect(new Rect(x, y, x+width, y+height), mFill);
  215.         }
  216.        
  217.         /**
  218.          * Draws an filled round-cornered rectangle using this graphics context's current color.
  219.          * The left and right edges of the rectangle are at x and x + width, respectively.
  220.          * The top and bottom edges of the rectangle are at y and y + height.
  221.          */
  222.         public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight){
  223.             mCanvas.drawRoundRect(new RectF(x, y, x+width, y+height), arcWidth, arcHeight, mFill);
  224.         }
  225.        
  226.         /**
  227.          * Draws the fill of a circular or elliptical arc covering the specified rectangle.
  228.             A positive value indicates a counter-clockwise rotation while a negative value indicates a clockwise rotation. <br>
  229.             <b>note: this behavior is backwards compared to Android's normal drawArc API which draws in a clockwise rotation.</b>
  230.          */
  231.         public void fillArc(int x, int y, int width, int height, int startAngle, int sweep){
  232.             mCanvas.drawArc(new RectF(x, y, x + width, y + height), startAngle, -sweep, false, mFill);
  233.         }
  234.        
  235.         /**
  236.          * @param color select colors easily by
  237.          * the {@link Color} class static variables. <br>
  238.          * for example setColor(Color.RED);<br>
  239.          * This is the same API as swing except for in swing the static variable
  240.          * is a class named Color rather than an int. <br>
  241.          * You can also use a HEX value 0xAARRGGBB the AA being alpha, to get the color
  242.          * red you would use setColor(0x00FF0000);<br>
  243.          */
  244.         public void setColor(int color){
  245.             mOutline.setColor(color);
  246.             mFill.setColor(color);
  247.         }
  248.        
  249.         /**
  250.          * Draws the bitmap to the screen
  251.          * @param bitmap to draw
  252.          * @param x value for top left corner
  253.          * @param y value for top left corner
  254.          */
  255.         public void setBitmap(Bitmap bitmap, float x, float y){
  256.             mCanvas.drawBitmap(bitmap, x, y, null);
  257.         }
  258.        
  259.         /**
  260.          * Calls {@link #setBitmap(Bitmap, float, float)} passing in 0, 0 for the location
  261.          * @param bitmap to draw
  262.          */
  263.         public void setBitmap(Bitmap bitmap){
  264.             setBitmap(bitmap, 0, 0);
  265.         }
  266.        
  267.         /**
  268.          * Saves this view as a jpg<br>
  269.          * Stored in {@link Environment#DIRECTORY_PICTURES}<br>
  270.          * This will typically be /sdcard/pictures
  271.          * @param filename
  272.          */
  273.         public void saveScreenToJPG(String filename){
  274.             if(filename == null) throw new NullPointerException("You must supply a filename.");
  275.             if(mBitmap == null) throw new NullPointerException("Screen buffer has not been allocated yet.");
  276.             if(!filename.endsWith(".jpg") || !filename.endsWith(".jpeg") || !filename.endsWith(".JPG") || !filename.endsWith(".JPEG")) filename += ".jpg";
  277.             File pictureDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
  278.             File pictureLoc = new File(pictureDirectory, filename);
  279.             try{
  280.                 FileOutputStream out = new FileOutputStream(pictureLoc);
  281.                 BufferedOutputStream stream = new BufferedOutputStream(out);
  282.                 mBitmap.compress(CompressFormat.JPEG, 100, stream);
  283.                 out.close();
  284.                 //makes picture show up in the gallery app
  285.                 MediaScannerConnection.scanFile(mActivity, new String[]{pictureLoc.getPath()}, null, null);
  286.             } catch (FileNotFoundException e) {
  287.                 e.printStackTrace();
  288.             } catch (IOException e) {
  289.                 e.printStackTrace();
  290.             }
  291.            
  292.         }
  293.        
  294.     }  
  295. }