Amazon Gift Cards

Saturday, December 25, 2010

Merry Christmas, Happy New Year, Android 2010, Android 2011

First of all Merry Christmas, and i'll be going into hibernation mode until the new year comes so Happy New Year as well :)

Android in 2010
* Our little green friend has been on its way to world domination, we just launch a new one into the outer space (Which later would be known as the origin of the terminators)
* Android is found in multiple devices, from Phones, to Tablets (Galaxy Tab having 10M sold), to Google TV (my sister in US got me one :-] ), and a lot more
* Froyo & Gingerbread released, Market got its much awaited update, rooting/custom roms/xda are still strong and awesome
* People still call upon fragmentation on Android, yes it is but i would say its just fragmented between low end device and high end device which is better then the linux/unix fragmentation, and unless you're a game programmer the chances you would get this hardcore fragmentation is really less.

Our Site
* This year has been a slow year for TutorialForAndroid.com and i hope i could make more tutorials next year
* Last year i shown i was doing something that could build android app easier, I announced it way too early and then Google created App Creator (I suggest everyone to give it a try), and i stopped the development and move on with something else like ShootAndLearn app

Android 2011
* Android would penetrate more market with Google TV having its app features, Tablets popping out left and right, PSP2 capturing the gaming community
* Android would not slow down its development, release often is better to push technology forward and Android is still young and evolving


* Quick Prediction on the future of Android (2011 and beyond)
* Finally i'll work for Google (ahahha) or be an Android programmer (I love WebProgramming too especially frontend technology like Javascript,Actionscript and CSS, yes Android is also frontend)
* PS4 would be announced as Google TV with PS and PSN
* Android would benefit from Chrome OS and vice versa (More apps would be web centric via webview)
* Java would not be the only language you can code Android with (currently you could do it) but future would be better (Javascript, Python or Ruby please)
* Android ndk would/should be married to Google Native Client (used in Chrome)
* O3D, WebGL, more HTML5 features to include in future version of Android
* Android would have WAC/Bondi features where you could call native functions from any website given you would grant them permission, Chrome OS might be the first to try this

As you can see most of my prediction expect PS4 is actually Android meeting Chrome OS, like what Eric Schmidt stated Android would eventually marry Chrome OS (Android 5.0?), this might not happen in 1 year time but most of the technologies between them are just overlapping each other and it make sense for them to meet later on (currently its still not ideal for it to happen).

To conclude our green friend has and would remain strong and I here would try to help more friends to get into the green robot army :) Merry Christmas and Happy New year to all of you

Tuesday, December 14, 2010

Previewing while Drawing with Canvas in Android

After my site being gone from the web yesterday, its back :) it happens to be a blogger bug. Anyway i got a lot of request on how to preview your drawing, and continue our Drawing with Canvas series, here is how to preview while drawing.

Notes
• The files are uploaded in http://goo.gl/ecHpE
• The project was build in IntelliJ and it should be easy to import to Eclipse

What Do I Need
DrawingSurface
public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
  public boolean isDrawing = true;
  public DrawingPath previewPath;

  private Handler previewDoneHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
      isDrawing = false;
    }
  };

  class DrawThread extends Thread{
    @Override
    public void run() {
      commandManager.executeAll(c,previewDoneHandler);
      previewPath.draw(c);
    }
  };
}



Drawing Activity
public class DrawingActivity extends Activity implements View.OnTouchListener{
  public void onCreate(Bundle savedInstanceState) {
    drawingSurface.previewPath = new DrawingPath();
    drawingSurface.previewPath.path = new Path();
    drawingSurface.previewPath.paint = getPreviewPaint();
    ...
  }
  private Paint getPreviewPaint(){
    final Paint previewPaint = new Paint();
    previewPaint.setColor(0xFFC1C1C1);
    previewPaint.setStyle(Paint.Style.STROKE);
    previewPaint.setStrokeJoin(Paint.Join.ROUND);
    previewPaint.setStrokeCap(Paint.Cap.ROUND);
    previewPaint.setStrokeWidth(3);
    return previewPaint;
  }

  public boolean onTouch(View view, MotionEvent motionEvent) {
    if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
      currentBrush.mouseDown(drawingSurface.previewPath.path, motionEvent.getX(), motionEvent.getY());
    }else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
      currentBrush.mouseMove(drawingSurface.previewPath.path, motionEvent.getX(), motionEvent.getY());
    }else if(motionEvent.getAction() == MotionEvent.ACTION_UP){
      currentBrush.mouseUp(drawingSurface.previewPath.path, motionEvent.getX(), motionEvent.getY());
      drawingSurface.previewPath.path = new Path();
    }
  }
}



Quick Explanation
Ads from Amazon:
Explanation
public boolean isDrawing = true;
Lets introduce something that would tell our app if we are drawing or not.

public DrawingPath previewPath;
Here we create another DrawingPath which would only do the preview for us

private Handler previewDoneHandler = new Handler(){
  @Override
  public void handleMessage(Message msg) {
    isDrawing = false;
  }
};

Here we create a handler to tell our app to stop drawing at the end of the last path it has drawn (this function should named differently, ahhah)

class DrawThread extends Thread{
  @Override
  public void run() {
    commandManager.executeAll(c,previewDoneHandler);
    previewPath.draw(c);
  }
};

Here you draw the preview path and pass our complete handler to stop our app from drawing over and over

public void onCreate(Bundle savedInstanceState) {
  drawingSurface.previewPath = new DrawingPath();
  drawingSurface.previewPath.path = new Path();
  drawingSurface.previewPath.paint = getPreviewPaint();
  ...
private Paint getPreviewPaint(){
  ...
}

Here we just initialize the previewPath with a different path (a kinda gray paint, 0xFFC1C1C1)

public boolean onTouch(View view, MotionEvent motionEvent) {
  if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
nbsp;   currentBrush.mouseDown(drawingSurface.previewPath.path, motionEvent.getX(), motionEvent.getY());
  }else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
    currentBrush.mouseMove(drawingSurface.previewPath.path, motionEvent.getX(), motionEvent.getY());
  }else if(motionEvent.getAction() == MotionEvent.ACTION_UP){
    currentBrush.mouseUp(drawingSurface.previewPath.path, motionEvent.getX(), motionEvent.getY());
    drawingSurface.previewPath.path = new Path();
  }
}

Here we use the concept we understood from brushes Read the explanation here

Hope this helps :)

Wednesday, December 8, 2010

Drawing with Canvas in Android, Brushes

Continuing with our Drawing in Canvas series, let us see how to implement brushes.


Introduction
Drawing lines is boring, lets draw something else

Notes
• We would introduce a new package com.almondmendoza.drawings.brush
• The files are uploaded in http://goo.gl/ecHpE
• The project was build in IntelliJ and it should be easy to import to Eclipse

What Do I Need
IBrush.java
public interface IBrush {
    public void mouseDown( Path path, float x, float y);
    public void mouseMove( Path path, float x, float y);
    public void mouseUp( Path path, float x, float y);
}


Brush.java
public class Brush implements  IBrush {
    public void mouseDown(Path path, float x, float y) {
        // add codes here if it would affect every brush
    }

    public void mouseMove(Path path, float x, float y) {
        // add codes here if it would affect every brush
    }

    public void mouseUp(Path path, float x, float y) {
        // add codes here if it would affect every brush
    }
}



Pen.java
public class PenBrush extends Brush{
    @Override
    public void mouseDown(Path path, float x, float y) {
        path.moveTo( x, y );
        path.lineTo(x, y);
    }

    @Override
    public void mouseMove(Path path, float x, float y) {
        path.lineTo( x, y );
    }

    @Override
    public void mouseUp(Path path, float x, float y) {
        path.lineTo( x, y );
    }
}


CircleBrush.java
public class CircleBrush extends Brush{
    @Override
    public void mouseMove(Path path, float x, float y) {
        path.addCircle(x,y,10,Path.Direction.CW);
    }
}


DrawingActivity.java
public class DrawingActivity extends Activity implements View.OnTouchListener{
    ...
    private Brush currentBrush;
    public void onCreate(Bundle savedInstanceState) {
        ...
        currentBrush = new PenBrush();
        ...
    }

    public boolean onTouch(View view, MotionEvent motionEvent) {
        if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
            currentBrush.mouseDown(currentDrawingPath.path, motionEvent.getX(), motionEvent.getY());
        } else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
            currentBrush.mouseMove( currentDrawingPath.path, motionEvent.getX(), motionEvent.getY() );
        } else if(motionEvent.getAction() == MotionEvent.ACTION_UP){
            currentBrush.mouseUp( currentDrawingPath.path, motionEvent.getX(), motionEvent.getY() );
            drawingSurface.isDrawing = true;
        }
        return true;
    }

    public void onClick(View view){
        switch (view.getId()){
            ...
            case R.id.circleBtn:
                currentBrush = new CircleBrush();
                break;
            case R.id.pathBtn:
                currentBrush = new PenBrush();
                break;
        }
    }



Quick Explanation
Ads from Amazon:
Explanation
public interface IBrush {
  public void mouseDown( Path path, float x, float y);
  public void mouseMove( Path path, float x, float y);
  public void mouseUp( Path path, float x, float y);
}

We begin by creating a brush interface so that our brushes would be united :)

public class Brush implements IBrush {
  ...
}

Our brush class would serve as base classes for our other brushes, here we can implement codes that would be shared across different brushes

public class PenBrush extends Brush{ ... }
From our previous article from the series we had implemented these codes directly on onTouch function on DrawingActivity, here we just move it to its own Brush class.

public class CircleBrush extends Brush{
  @Override
  public void mouseMove(Path path, float x, float y) {
    path.addCircle(x,y,10,Path.Direction.CW);
  }
}

In here we only make use of the mouseMove of our Brush class, as you can see we have path.addCircle where we could make other brushes by changing this to other function or adding more then one path (For other shapes available kindly refer to the Path Reference

public boolean onTouch(View view, MotionEvent motionEvent) {
  if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
    currentBrush.mouseDown(currentDrawingPath.path, motionEvent.getX(), motionEvent.getY());
  }else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
    currentBrush.mouseMove( currentDrawingPath.path, motionEvent.getX(), motionEvent.getY() );
  }else if(motionEvent.getAction() == MotionEvent.ACTION_UP){
    currentBrush.mouseUp( currentDrawingPath.path, motionEvent.getX(), motionEvent.getY() );
    drawingSurface.isDrawing = true;
  }
  return true;
}

We rewrote the function to use our brushes to do the paths so that we could change the brush and not care about this function.

public void onClick(View view){
  switch (view.getId()){
    ...
    case R.id.circleBtn:
      currentBrush = new CircleBrush();
    break;
    case R.id.pathBtn:
      currentBrush = new PenBrush();
    break;
  }
}

This is now we change brushes

Conclusion
To add new brushes, just create a new class that extends the Brush class.

Tuesday, December 7, 2010

My Battery Status 2.1.0

Been fixing the UI part of My battery status for days, now its live, anyone can search them on the market (search for com.almondmendoza.monBattery). Next article should be back to our series :)

Friday, December 3, 2010

TutorialForAndroid first 1000 visit

After 2-3 years of this site, I finally hit the 1000 visit one single day, which just means i'm atleast helping 1000 (if all reads the tutorial) or a lot of programmers to Android with these tutorials :)

I would like to thanks everyone, and as we go forward, i would like focus on making series (like the drawing series) and as a new step to this site and my career, im opening up suggestions on what i could blog thus making use of google moderator http://www.google.com/moderator/#15/e=40510&t=40510.40, anyone can suggest a topic (please be warned that i do need time to learn them as well and only after work)

Thanks again

Sunday, November 28, 2010

Soft Kitty - Non Android

Once in a while i would post non-android article and here is one of them.

Anyone watch the big bang theory must know this song, if not here is a video


And here is a guitar tab, ahhah
2 or B |--8-5-5--6-3-3--1-3-5-6-8---8-5-5--6-3-3--1-3-1--| (repeat nth times)

:)

Thursday, November 25, 2010

Using library with resources in IntelliJ and Android

As my previous articles indicates, im coding more Android in IntelliJ then eclipse (main reason is that it will let you forget you have a mouse). For those new to IntelliJ, like me, here is how i set up the library in IntelliJ so that both resources and code could be used.


Notes
• Im new to IntelliJ so if im doing something wrong, kindly comment below :)
• As of writing the resources between library cant be handle properly when compiled (you can still do the coding with it) thus we need the help of command line (ant install, adb install/uninstall), on the Bug tracker it was reported to be fine in nightly.

What Do I Need
• As of now you need the EAP of IntelliJ
• Lastest Android SDK
• You need to know how to create a project
• You need to know how to create a library



Instruction
1) Open your project's module settings


2) In Modules, click the add new module (see image below)

3) Select your library if you had previously created one

4) Browse to your libraries path/directory. and select the file with the extension .iml

5) First click on your project (the red circle) then on the dependencies tab, click on add then Module dependencies (it shall have only one module)




Easy Updates 468x60

Command line
So you can code with your favorite IDE and now you want to debug it on the emulator. you could do (please refer to Developing in other IDE (You must have ant in your OS)
cd /path/to/your/project
ant debug


It will then tell you that where the apk is at
debug:
[echo] Running zip align on final apk...
[echo] Debug Package: /path/to/your/project/bin/shootAndLearn-debug.apk


Now you have to install it on the emulator, please refer to Android Debug Bridge page
adb uninstall com.almondmendoza.shootAndLearn
adb install bin/shootAndLearn-debug.apk


adb uninstall com.almondmendoza.shootAndLearn
We have to uninstall the apk from the emulator first before

adb install bin/shootAndLearn-debug.apk
installing it


Conclusion
I know the debugging part is kinda hard right now but the development/coding part is certainly a lot better (got to love the ctrl+w, ctrl+shift+a shortcuts) :)

Sunday, November 21, 2010

Drawing with Canvas in Android, Saving your drawings

Continuing with our Drawing in Canvas series, let us see how to save your drawings
Update:
May 5, 2011 - If saving the image is not that fine, this could come in handy http://stackoverflow.com/questions/5243547/decode-byte-array-to-bitmap-that-has-been-compressed-in-java

Introduction
We draw and saw our drawings are good, now lets save them

Notes
• The files are uploaded in http://goo.gl/ecHpE
• The project was build in IntelliJ and it should be easy to import to Eclipse


What Do I Need

DrawingSurface
public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
  private Bitmap mBitmap;
  private ...
  class DrawThread extends  Thread{
    ...
    @Override
    public void run() {
      Canvas canvas = null;
      while (_run){
        try{
          canvas = mSurfaceHolder.lockCanvas(null);
          if(mBitmap == null){
            mBitmap =  Bitmap.createBitmap (1, 1, Bitmap.Config.ARGB_8888);;
          }
          final Canvas c = new Canvas (mBitmap);
          c.drawColor(0, PorterDuff.Mode.CLEAR);
          commandManager.executeAll(c);
          canvas.drawBitmap (mBitmap, 0,  0,null);
        } finally {
          mSurfaceHolder.unlockCanvasAndPost(canvas);
        }
      }
    }
  }

  public Bitmap getBitmap(){
    return mBitmap;
  }

  public void surfaceChanged(SurfaceHolder holder, int format, int width,  int height) {
    // TODO Auto-generated method stub
    mBitmap =  Bitmap.createBitmap (width, height, Bitmap.Config.ARGB_8888);;
  }
}

DrawingActivity
public class DrawingActivity extends Activity implements View.OnTouchListener{
  ...
  private static File APP_FILE_PATH = new File("/sdcard/TutorialForAndroidDrawings");

  public void onClick(View view){
    switch (view.getId()){
      ...
      case R.id.saveBtn:
        final Activity currentActivity  = this;
        Handler saveHandler = new Handler(){
          @Override
          public void handleMessage(Message msg) {
            final AlertDialog alertDialog = new AlertDialog.Builder(currentActivity).create();
            alertDialog.setTitle("Saved 1");
            alertDialog.setMessage("Your drawing had been saved :)");
            alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
              public void onClick(DialogInterface dialog, int which) {
                return;
              }
            });
            alertDialog.show();
          }
        } ;
         new ExportBitmapToFile(this,saveHandler, drawingSurface.getBitmap()).execute();
      break;
    }
  }


  private class ExportBitmapToFile extends AsyncTask {
    private Context mContext;
    private Handler mHandler;
    private Bitmap nBitmap;

    public ExportBitmapToFile(Context context,Handler handler,Bitmap bitmap) {
      mContext = context;
      nBitmap = bitmap;
      mHandler = handler;
    }

    @Override
    protected Boolean doInBackground(Intent... arg0) {
      try {
        if (!APP_FILE_PATH.exists()) {
          APP_FILE_PATH.mkdirs();
        }

        final FileOutputStream out = new FileOutputStream(new File(APP_FILE_PATH + "/myAwesomeDrawing.png"));
        nBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
        out.flush();
        out.close();
        return true;
      }catch (Exception e) {
        e.printStackTrace();
      }
      //mHandler.post(completeRunnable);
      return false;
    }

    @Override
    protected void onPostExecute(Boolean bool) {
      super.onPostExecute(bool);
      if ( bool ){
        mHandler.sendEmptyMessage(1);
      }
    }
  }
}


Quick Explanation
Ads from Amazon:
Explanation
if(mBitmap == null){
  mBitmap = Bitmap.createBitmap (1, 1, Bitmap.Config.ARGB_8888);;
}
final Canvas c = new Canvas (mBitmap);
c.drawColor(0, PorterDuff.Mode.CLEAR);
commandManager.executeAll(c);

This is the core of the saving part, in order for our drawing to be exported we have to create a canvas with bitmap to draw upon to, See Canvas Class for more info.


canvas.drawBitmap (mBitmap, 0, 0,null);
We put our bitmap to our original canvas (the surfaceView's canvas) so that we can see our drawings


public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  mBitmap = Bitmap.createBitmap (width, height, Bitmap.Config.ARGB_8888);;
}

We would have to recreate our bitmap when we change the orientation (The drawings will currently be removed)


final Activity currentActivity = this;
Handler saveHandler = new Handler(){ ... }

We cant call the UI tread from another thread so we pass a handler to our AsyncTask, see Using Handler in Android for more information on Handlers

private class ExportBitmapToFile extends AsyncTask {
  private Context mContext;
  private Handler mHandler;
  private Bitmap nBitmap;

  public ExportBitmapToFile(Context context,Handler handler,Bitmap bitmap) {
    mContext = context;
    nBitmap = bitmap;
    mHandler = handler;
  }

  @Override
  protected Boolean doInBackground(Intent... arg0) {
    try {
      if (!APP_FILE_PATH.exists()) {
        APP_FILE_PATH.mkdirs();
      }

      final FileOutputStream out = new FileOutputStream(new File(APP_FILE_PATH + "/myAwesomeDrawing.png"));
      nBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
      out.flush();
      out.close();
      return true;
    }catch (Exception e) {
      e.printStackTrace();
    }
    //mHandler.post(completeRunnable);
    return false;
  }


  @Override
  protected void onPostExecute(Boolean bool) {
    super.onPostExecute(bool);
    if ( bool ){
      mHandler.sendEmptyMessage(1);
    }
  }
}

In order for us to export the bitmap and not hard the UX of our app, we need to create a background thread for it, for more information on AsyncTask see the AsyncTask Class and Painless Threading

final FileOutputStream out = new FileOutputStream(new File(APP_FILE_PATH + "/myAwesomeDrawing.png"));
nBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();

This is default Java feature, if your now from Java then this just mean that you create a buffer where when we use that in mBitmap.compress the compressed bitmap would be buffered into that FileOutputStream (i hope i was clear in this. haha)


Reference
Most of the stuff here were back in 2009, most of them are in Google Groups.

Wednesday, November 17, 2010

Drawing with Canvas in Android, Undo/Redo with Command Pattern

Update - Nov 21, 2010
Created a series over this topic over at Drawing with Canvas Series, more articles would appear in the future :)

Continuing our Drawing with Canvas in Android, lets implement Undo and Redo with Command Pattern

Introduction
We draw and make mistake, and when we do we may want to undo it and when we undo we might want to redo it. Lets use a common design pattern in dealing with undo (I believe this is a modified command pattern for the command manager but i might be wrong)

Notes
• This is a continuation of Drawing with Canvas in Android Renewed
• The files are uploaded in http://goo.gl/ecHpE
• The project was build in IntelliJ and it should be easy to import to Eclipse


What Do I Need
ICanvasCommand
public interface ICanvasCommand {
  public void draw(Canvas canvas);
  public void undo();
}


DrawingPath
public class DrawingPath implements ICanvasCommand{
  public Path path;
  public Paint paint;

  public void draw(Canvas canvas) {
    canvas.drawPath( path, paint );
  }

  public void undo() {
    //Todo this would be changed later
  }
}


CommandManager
public class CommandManager {
  private List currentStack;
  private List redoStack;

  public  CommandManager(){
    currentStack = Collections.synchronizedList(new ArrayList());
    redoStack = Collections.synchronizedList(new ArrayList());
  }

  public void addCommand(DrawingPath command){
    redoStack.clear();
    currentStack.add(command);
  }

  public void undo (){
    final int length = currentStackLength();
    if ( length > 0) {
      final DrawingPath undoCommand = currentStack.get(  length - 1  );
      currentStack.remove( length - 1 );
      undoCommand.undo();
      redoStack.add( undoCommand );
    }
  }

  public int currentStackLength(){
    final int length = currentStack.toArray().length;
    return length;
  }

  public void executeAll( Canvas canvas){
    if( currentStack != null ){
      synchronized( currentStack ) {
        final Iterator i = currentStack.iterator();
        while ( i.hasNext() ){
          final DrawingPath drawingPath = (DrawingPath) i.next();
          drawingPath.draw( canvas );
        }
      }
    }
  }

  public boolean hasMoreRedo(){
    return  redoStack.toArray().length > 0;
  }

  public boolean hasMoreUndo(){
    return  currentStack.toArray().length > 0;
  }

  public void redo(){
    final int length = redoStack.toArray().length;
    if ( length > 0) {
      final DrawingPath redoCommand = redoStack.get(  length - 1  );
      redoStack.remove( length - 1 );
      currentStack.add( redoCommand );
    }
  }
}


DrawingSurface
public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
  private CommandManager commandManager;

  public DrawingSurface(Context context, AttributeSet attrs) {
    ...
    commandManager = new CommandManager();
    ...
  }

  class DrawThread extends  Thread{
    ...
    @Override
    public void run() {
      Canvas canvas = null;
      while (_run){
        try{
          canvas = mSurfaceHolder.lockCanvas(null);
          canvas.drawColor(0, PorterDuff.Mode.CLEAR);
          commandManager.executeAll(canvas);
        ....
  }

  public void addDrawingPath (DrawingPath drawingPath){
    commandManager.addCommand(drawingPath);
  }

  public boolean hasMoreRedo(){
    return commandManager.hasMoreRedo();
  }

  public void redo(){
    commandManager.redo();
  }

  public void undo(){
    commandManager.undo();
  }

  public boolean hasMoreUndo(){
    return commandManager.hasMoreUndo();
  }
}


DrawingActivity
See the source should be simple enough to be understood :)



Ads from Amazon:
Explanation
public interface ICanvasCommand {
  public void draw(Canvas canvas);
  public void undo();
}

In undo command pattern based we need need 2 methods, one is execute and the other is undo (we wont use undo currently)


public class DrawingPath implements ICanvasCommand{
  public Path path;
  public Paint paint;
  public void draw(Canvas canvas) {
    canvas.drawPath( path, paint );
  }
  public void undo() {
    //Todo this would be changed later
  }
}

Let us now implement our interface, the code should be easy to understand. canvas.drawPath( path, paint) would draw our path with the object's paint into our class.


currentStack = Collections.synchronizedList(new ArrayList());
redoStack = Collections.synchronizedList(new ArrayList());

We create 2 List (Its actually a Stack but seems Stack cannot be thread-safe and I dont freakin understand why there are a lot of Array variation in Java, its so messy), one called currentStack for the current paths, another is redoStack where we put the undo commands so we could do redos.


public void addCommand(DrawingPath command){
  redoStack.clear();
  currentStack.add(command);
}

Everytime we add a new command, we should clear the redoStack


Ads from Amazon:
public void undo (){
  final int length = currentStackLength();
  if ( length > 0) {
    final DrawingPath undoCommand = currentStack.get( length - 1 );
    currentStack.remove( length - 1 );
    undoCommand.undo();
    redoStack.add( undoCommand );
  }
}

When we do an undo, we pop the last command from the currentStack and push it to our redoStack. As you can see we implemented undoCommand.undo() we did this incase in the future we have some logics added to our undo function


public void executeAll( Canvas canvas){
  if( currentStack != null ){
    synchronized( currentStack ) {
      final Iterator i = currentStack.iterator();
      while ( i.hasNext() ){
        final DrawingPath drawingPath = (DrawingPath) i.next();
        drawingPath.draw( canvas );
      }
    }
  }
}

We loop through our currentStack and do the execute part (.draw) from our command pattern.


canvas = mSurfaceHolder.lockCanvas(null);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
commandManager.executeAll(canvas);

In order for our undo/redo to work we have to somehow clear the canvas and drawColor(0, PorterDuff.Mode.CLEAR) helps us with that


Some of the codes are, i believe, logical thus i skip the explanation on them.

Saturday, November 13, 2010

Drawing with Canvas in Android Renewed

Update - Nov 21, 2010
Created a series over this topic over at Drawing with Canvas Series, more articles would appear in the future :)

Back one year ago, i blogged about Drawing with Canvas in Android, at that time i was creating a drawing app that never get released (lazy me). Now im planning to redo everything and share my learnings as i go on (I'm still doing the Shoot and Learn on the side). From the simple tutorial on how to draw canvas in android, lets explode this area further.

Introduction
Based on the Drawing with Canvas in Android lets put the SurfaceView into a separate class (you should know how to use custom view), create a DrawingPath class which would contain our Path and Paint object, and create a DrawingActivity where our touch events, buttons to change colors are located.

Notes
• The package i would use through this tutorial is com.almondmendoza.drawings
• The individual source are located at http://goo.gl/5GulF while the full ones is at https://sites.google.com/site/tutorialsformobileprogramming/android-tutorials/android-files
• In this tutorial we wont handle clearing up the images, undos/redos and screen rotations (all in future articles :) )


What Do I Need
Drawing Activity
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    ....
>
    <com.almondmendoza.drawings.DrawingSurface
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/drawingSurface"
    />
    <LinearLayout
            .....
    >
    ......
    </LinearLayout>
</RelativeLayout>


Main Activity
Intent drawIntent = new Intent(this, DrawingActivity.class);
startActivity( drawIntent);


DrawingPath.java
public class DrawingPath {
  public Path path;
  public Paint paint;
}


Drawing Activity
public class DrawingActivity extends Activity implements View.OnTouchListener{
  private DrawingSurface drawingSurface;
  private DrawingPath currentDrawingPath;
  private Paint currentPaint;

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.drawing_activity);
    setCurrentPaint();
    drawingSurface = (DrawingSurface) findViewById(R.id.drawingSurface);
    drawingSurface.setOnTouchListener(this);
  }

  private void setCurrentPaint(){
    currentPaint = new Paint();
    currentPaint.setDither(true);
    currentPaint.setColor(0xFFFFFF00);
    currentPaint.setStyle(Paint.Style.STROKE);
    currentPaint.setStrokeJoin(Paint.Join.ROUND);
    currentPaint.setStrokeCap(Paint.Cap.ROUND);
    currentPaint.setStrokeWidth(3);
  }

  public boolean onTouch(View view, MotionEvent motionEvent) {
    if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
      currentDrawingPath = new DrawingPath();
      currentDrawingPath.paint = currentPaint;
      currentDrawingPath.path = new Path();
      currentDrawingPath.path.moveTo(motionEvent.getX(), motionEvent.getY());
      currentDrawingPath.path.lineTo(motionEvent.getX(), motionEvent.getY());
    }else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
      currentDrawingPath.path.lineTo(motionEvent.getX(), motionEvent.getY());
    }else if(motionEvent.getAction() == MotionEvent.ACTION_UP){
      currentDrawingPath.path.lineTo(motionEvent.getX(), motionEvent.getY());
      drawingSurface.addDrawingPath(currentDrawingPath);
    }
    return true;
  }

  public void onClick(View view){
    switch (view.getId()){
      case R.id.colorRedBtn:
        currentPaint = new Paint();
        currentPaint.setDither(true);
        currentPaint.setColor(0xFFFF0000);
        currentPaint.setStyle(Paint.Style.STROKE);
        currentPaint.setStrokeJoin(Paint.Join.ROUND);
        currentPaint.setStrokeCap(Paint.Cap.ROUND);
        currentPaint.setStrokeWidth(3);
      break;
      case R.id.colorBlueBtn:
        currentPaint = new Paint();
        currentPaint.setDither(true);
        currentPaint.setColor(0xFF00FF00);
        currentPaint.setStyle(Paint.Style.STROKE);
        currentPaint.setStrokeJoin(Paint.Join.ROUND);
        currentPaint.setStrokeCap(Paint.Cap.ROUND);
        currentPaint.setStrokeWidth(3);
      break;
      case R.id.colorGreenBtn:
        currentPaint = new Paint();
        currentPaint.setDither(true);
        currentPaint.setColor(0xFF0000FF);
        currentPaint.setStyle(Paint.Style.STROKE);
        currentPaint.setStrokeJoin(Paint.Join.ROUND);
        currentPaint.setStrokeCap(Paint.Cap.ROUND);
        currentPaint.setStrokeWidth(3);
      break;
    }
  }
}



Drawing Surface
public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {
  private Boolean _run;
  protected DrawThread thread;

  public DrawingSurface(Context context, AttributeSet attrs) {
...
  }

  public void addDrawingPath (DrawingPath drawingPath){
    thread.addDrawingPath(drawingPath);
  }

  class DrawThread extends  Thread{
    private SurfaceHolder mSurfaceHolder;
    private List mDrawingPaths;
    public DrawThread(SurfaceHolder surfaceHolder){
      mSurfaceHolder = surfaceHolder;
      mDrawingPaths = Collections.synchronizedList(new ArrayList());
    }

...

    public void addDrawingPath(DrawingPath drawingPath){
      mDrawingPaths.add( drawingPath );
    }

    @Override
    public void run() {
      Canvas canvas = null;
      while (_run){
        try{
          canvas = mSurfaceHolder.lockCanvas(null);
          synchronized(mDrawingPaths) {
            Iterator i = mDrawingPaths.iterator();
            while (i.hasNext()){
              final DrawingPath drawingPath = (DrawingPath) i.next();
              canvas.drawPath(drawingPath.path, drawingPath.paint);
            }
          }
        } finally {
          mSurfaceHolder.unlockCanvasAndPost(canvas);
        }
      }
    }
  }
....
}






Explanation
<com.almondmendoza.drawings.DrawingSurface
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:id="@+id/drawingSurface"
/>

We start off by using our custom view in our xml, its as simple as creating a class and using it on the layout.


public class DrawingPath {
  public Path path;
  public Paint paint;
}

From Drawing with Canvas in Android we learn to put an ArrayList of Path which have a single color, for us to have different colors on different path, we create a class which would be an List in our DrawThread later on.


private Paint currentPaint;
....
private void setCurrentPaint(){
  currentPaint = new Paint();
  currentPaint.setDither(true);
  currentPaint.setColor(0xFFFFFF00);
  currentPaint.setStyle(Paint.Style.STROKE);
  currentPaint.setStrokeJoin(Paint.Join.ROUND);
  currentPaint.setStrokeCap(Paint.Cap.ROUND);
  currentPaint.setStrokeWidth(3);
}

Here we create a Paint that would serve as our current paint, and set the currentPaint at the start of our activity.


  public void onClick(View view){
  switch (view.getId()){
    case R.id.colorRedBtn:
      currentPaint = new Paint();
      currentPaint.setDither(true);
      currentPaint.setColor(0xFFFF0000);
...
    break;
    case R.id.colorBlueBtn:
      currentPaint = new Paint();
      currentPaint.setDither(true);
      currentPaint.setColor(0xFF00FF00);
...

This is how we change the currentPaint's color, since we use the Paint object, you could use any of its property/methods thus making every Path beautiful :)


  public boolean onTouch(View view, MotionEvent motionEvent) {
  if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
    currentDrawingPath = new DrawingPath();
    currentDrawingPath.paint = currentPaint;
    currentDrawingPath.path = new Path();
    ....
    drawingSurface.addDrawingPath(currentDrawingPath);
  }
  return true;
}

In the previous tutorial, we bind our onTouch on the surfaceView directly, now we bind it in our activity, this way we could control the logic of the touches better (where you would apply your own shared touch library) and you could do things that doesnt harm the SurfaceView/Canvas.


public DrawThread(SurfaceHolder surfaceHolder){
  mSurfaceHolder = surfaceHolder;
  mDrawingPaths = Collections.synchronizedList(new ArrayList());
}

As stated earlier we would create a List of DrawingPath, but in able to manipulate it while our thread is running we need to make sure that its thread-safe thus we call Collections.synchronizedList(new ArrayList()); (I'm not sure about this since i never used threads in other language besides Javascript's webworker)


  public void addDrawingPath (DrawingPath drawingPath){
    thread.addDrawingPath(drawingPath);
  }

From our activity we would pass a DrawingPath to our surfaceView which we would then pass it to our thread, we do this so that our thread would not be accessible to the outside world of our DrawingSurface, which i believe is better for we can inject logics that would deal with our SurfaceView before passing it to our thread.


public void addDrawingPath(DrawingPath drawingPath){
  mDrawingPaths.add( drawingPath );
}

From our DrawingSurface to our DrawThread, we pass the a DrawingPath and add it to our list


synchronized(mDrawingPaths) {
  Iterator i = mDrawingPaths.iterator();
  while (i.hasNext()){
    final DrawingPath drawingPath = (DrawingPath) i.next();
    canvas.drawPath(drawingPath.path, drawingPath.paint);
  }
}

Here we use the Iterator class to iterate over our DrawingPath list and draw our Path on the canvas.

Conclusion
Now we learn how to better put our codes and make sure it can be scale up (im a webdeveloper, ahha) in the future.

Hope this helps :)

Saturday, October 30, 2010

Take Picture in Android with MediaStore.ACTION_IMAGE_CAPTURE

Previously in Android when you want to capture an Image, you have to use SurfaceView and SurfaceHolder to preview the camera. MediaStore.ACTION_IMAGE_CAPTURE was introduced in Cupcake, Android 1.5, and has been the default way to capture images captured in Android.

What Do I Need
In Manafiest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

In your activity
private static final int TAKE_PHOTO_CODE = 1;

private void takePhoto(){
  final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempFile(this)) ); 
  startActivityForResult(intent, TAKE_PHOTO_CODE);
}

private File getTempFile(Context context){
  //it will return /sdcard/image.tmp
  final File path = new File( Environment.getExternalStorageDirectory(), context.getPackageName() );
  if(!path.exists()){
    path.mkdir();
  }
  return new File(path, "image.tmp");
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (resultCode == RESULT_OK) {
    switch(requestCode){
      case TAKE_PHOTO_CODE:
        final File file = getTempFile(this);
        try {
          Bitmap captureBmp = Media.getBitmap(getContentResolver(), Uri.fromFile(file) );
          // do whatever you want with the bitmap (Resize, Rename, Add To Gallery, etc)
        } catch (FileNotFoundException e) {
          e.printStackTrace();
        } catch (IOException e) {
          e.printStackTrace();
        }
      break;
    }
  }
}


Ads from Amazon:
Explanation
final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getTempFile(this) );
startActivityForResult(intent, TAKE_PHOTO_CODE);

This is the core of the code, here we call an intent from the MediaStore which would open up the camera app, then we pass the output path of the captured image to a temporary location (Always use a safe location to store the image). Here we use the Environment.getExternalStorageDirectory() which is our SDCard, again for safety reason check if the SDCard is present or not. Then we start the activity, expecting a result with code TAKE_PHOTO_CODE

final File file = getTempFile(this);
try {
Bitmap captureBmp = Media.getBitmap(getContentResolver(), Uri.fromFile(file) );
}...{}

Knowing where the output of the file will be, we would open that file and place it on a bitmap where we would do our magic

Conclusion
ACTION_IMAGE_CAPTURE has done a great job so that we wont implement our own implementation of the camera app, so use it.

Update History
   Jan 17, 2012 - Visual Update

Thursday, October 28, 2010

How to restart your own app in Android Tutorial

After launching (now refactoring) Shoot and Learn [ Market Link | AndroidPit.com Link ] , its time to write what i have learn.

Senario
You want to restart your app because of some preference/setting changed, or you just want to restart your app.

Notes
This might not be the best solution thus if you have a better one kindly comment below :)

Introduction
First we need our main activity to be a routing activity (if you came from the web, most framework do this where you have an index page where it routes other calls to its right controller). This main activity we shall call PreMainActivity, in this tutorial we would only put the restart logic on this activity, you can put things like preloader, first run activity, etc.


What Do I Need
In Manafiest.xml
<activity 
 android:name=".PreMainActivity"
 android:label="@string/app_name"
 android:launchMode="singleTop"
 android:configChanges="locale"
>
 <intent-filter>
  <action android:name="android.intent.action.MAIN" />
  <category android:name="android.intent.category.LAUNCHER" />
 </intent-filter>
</activity>
<activity android:name=".Main"
 android:configChanges="locale"
/>



In PreMainActivity.java
public class PreMainActivity extends Activity {
 public static Boolean ENABLE_RESTART = false;
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  ENABLE_RESTART = true;
  restartMain();
 }
 
 @Override
 public void onRestart() {
  super.onRestart();
  restartMain();
 }
   
 public void restartMain(){
  if(ENABLE_RESTART == true){
   Intent mainIntent = new Intent(this, Main.class);
   mainIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP  );
   startActivity(mainIntent);
   finish();
  }else{
   finish();
  }
  ENABLE_RESTART   = false;
 }    
}


In your activity where you want to trigger the restart
PreMainActivity.ENABLE_RESTART = true;
Intent i = new Intent(this,PreMainActivity.class);
i.addFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);



Explanation
<activity

android:name=".PreMainActivity"

.... />

As stated in our introduction we would use a PreMainActivity as the receiver of our main action.

public static Boolean ENABLE_RESTART = false;
In our activity we would have a static variable to check if the activity should restart or not.

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ENABLE_RESTART = true;
restartMain();
}

When our app is first launched we would need to turn the flag to true in order for our next activity to restart/start.

Intent mainIntent = new Intent(this, Main.class);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP );
startActivity(mainIntent);
finish();

With this code, i assumed that main is on the top of the activity stack therefore we could just relaunch it as clear the whole stack. See (http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP).

PreMainActivity.ENABLE_RESTART = true;
Intent i = new Intent(this,PreMainActivity.class);
i.addFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);

Combined with android:launchMode="singleTop" in our manifest file, we make sure that when we launch PreMainActivity we get a clear top, single top activity. Note I might be doing some redundancy on singletop flag.

Conclusion
This how you can restart your app but this is not the best solution, as stated above im in a refactoring mode, in where instead of having a static variable, i would pass data i.putExtra("RESTART", true); on the intent. Which is a better solution, but if you have any better idea please do comment below and ill try to be more active with this blog :)

Saturday, October 16, 2010

Shoot and Learn

After few months of developing an android app for fun, finally got to release one on the market :)
Firstly thanks to SK Lam (his daugher's blog), to my parents for letting me stay late, to my friends for their suppor, to all who tested the app and to everyone that would download it.

The app is an application for kids to learn objects around them by capturing it and learning it like flash cards. From the sound of that there shouldn't be anything special with the app right?
Yes and no, yes its a flash card app like other but no, it has a better UI and UX (i hope) and its colorful with different themes (Signs of being a frontend guy, ahah).

Another interesting aspect is the Language feature (which i would like to open source it later when its ready), in here users can crowd source the language translation so that the translation of the app would be from its user base and thats the fun part of it :)

There is still a lot of improvements on the app and on the codes level, so brace yourself for bugs.

Head over the market place and search for "shoottolearn" <-- easier to find it with this way

Next blogs would be sharing the how to do on the apps. Any features on my app that you guys want me to blog? Comment down below. Thanks

Wednesday, September 29, 2010

Non Android Post

I had a wonderful vacation last week (9 days in the Philippines), and one of my friend said that my blog is pure Android related and that i should post a non android one, and this is that post (beau ayan na po). But before i go through with it, coming is a Google DevFest 2010 here in Hong kong since i just had my long vacation, i cant attend this one, but for those interested join the GTUGS group of hong kong http://hk.gtugs.org/ for more information.

Day 1 - After arriving in my hometown, went to visit my Grandfather who had been in comma state for 1 year (i hope he gets well soon). After few hours when back to our house and sleep (I didnt sleep before the trip, lol)

Day 2 - Woke up at around 2pm, hah. Pack the stuff for the subic trip, at 6pm went to Festival mall in alabang to meet my university friends, travel at night to subic and arrived there at around 2am.

Day 3 - Looking for hotels in subic, one of the lady asked us if we want to do a short time, it was funny coz in the beginning it was 2 guys and 1 girl, then one of our girl friend came and the lady looked shocked, and when my friend said we were 8 in total, the lady looked puzzled. hahaha. We end up looking for other hotels.

After waking up and preparing and stuff, we went to Zoobic to see animals and do the safari ride (tiny safari), after that we went to Tree Top Adventure and the rides were amazing especially the 60 ft tree drop (http://www.youtube.com/watch?v=EZbHJG9WWZw&feature=related youtube video of some random people)

Ended the day in another hotel which is nicer, had talk sessions with friends, realized a lot of stuff from that talk.

Day 4 - Went back to Manila to meet other friends and had dinner with them.

Day 5 - Woke up at around 12nn, went back to my grandfather's place to sleep there, also a preparing for the next day (meet up with best friends in high school)

Day 6 - Woke up so early at 6am, went to EcoPark to see the LaMesa Dam and go wall climbing and rappelling(again). Missed my best friends so much that i went home at around 2am. Just stayed in starbucks in MOA.

Day 7 - When back to our home in Cavite, meet one of my final project's teammate and chat for awhile as she is about to leave for Malaysia. After that my korean friend arrived and we walked from my place to our dorms before (20 mins), to walter malt (20 mins) and back to our school (30mins), took us forever. When we arrived in our school we were just in our flipflop but the guard let us in. hah. at night we meet one of his friend and just played computer games.

Day 8 - Went to meet the daughter of one of our friend whom we are godfather to, whom we havent meet after she was baptized, hah. We had a great time buying her a mini drums. At night went back and rest, since there are no internet connection, i had composed a song which i havent finish.

Day 9 - Went to the 20th Anniversary of Unida church in our place, after that brought some stuff for the journey back to hk. In the afternoon, went back to HK. Arrived home at 12midnight, sleep at around 2am fixing bugs for a freelance.

Wow this post is long, amazing. Anyhow, the next post would be about an Android app that i had been developing for the last 2-3 months. Its an educational based app, and there is still a lot of improvements and bugs on it. haha. I would open up some modules of that app which i think would advice some aspect of what i had been fighting for (Localization).

Saturday, August 28, 2010

App Inventor by Hak5

Over the Hak5 darren shows how App Inventor, the software is made with scratch from MIT (http://scratch.mit.edu/). From my previous review, i showed how i hate the concept, now with scratch as its interface, its good for non programmer to start programming using this. Scratch's concept of blocks is amazing for non programmers to jump ahead on programming. Go and watch the latest episode of Hak5

Saturday, July 17, 2010

Paid Apps vs Apps with ads in Android

With Korea adding to the list of Android market having Paid apps, the question is, is it good to have your app as a paid app or have ads on it.

There are the markets where paid apps are available
Australia - (English)
Austria - (German)
Canada - (English)
France - (French)
Germany - (German)
Italy - (Italian)
Japan - (Japanese)
Netherlands - (Dutch)
New Zealand - (English)
Spain - (Spanish)
Switzerland - (French,German,Italian, Romansh)
United Kingdom - (English)
United States - (English)
Korea - (Korean)

If you look closely, just 14 out of 46 countries have paid apps, in these countires only 5 countries having English as their primary language, and all the other countries are of different languages. This language barrier is a big factor in selling your apps, especially if your app has a global target.

Why do you have to care about other languages?
As i stated before mobile is not the web. On the web, forums and blogs would copy your content and translate it to their native language or they could use tools like Google Translate or Yahoo BabelFish, mobile apps on the other hand could not be copied and recompiled to other languages and redistributed, thats why it is important that you cater atleast the biggest langauges like English, Chinese, French, Spanish, German, Arabic, Italian, etc.

What does the language have to do with your apps being paid or with ads?
If your app would be in English and you dont have plans to support other language, its pretty bad idea to make it as a paid app (users can forgive you for the ads if its not on their native language). And there are a lot of apps that are paid who are doing this and if your app is just the english language, kindly uncheck the non english speaking countries on the market (Some countries have a huge numbers of non-english speaking/reading so be kind to their paying users)

Conclusion
If English would be the only language in your app then dont go with paid apps.
If you do a paid app 32 other counties would not see your app, which some of them huge market like India (English as big second language) and China.

Android: resolution independence and high performance graphics

New Video added on http://sites.google.com/site/tutorialsformobileprogramming/android-videos titled "Android: resolution independence and high performance graphics "

Monday, July 12, 2010

App Inventor

Incase you didn't read the news today, App Inventor is announce, its a way to develop Android App without programming. And what do I have to say about it?

1. Kindly fix the GUI tool in eclipse before releasing some GUI tools for noobs when the SDK for developers cant work properly...

2. It would generate a lot of stupid application, since the market is already in a mess, it would be a lot more messier (yes its redundant) when this comes out. Yes there would be 1 or 2 that would be good that would came out from this but how many nonsense apps would be out there. Is the number of apps really that important to battle yourself with iOS when more than 50% of the apps are nonsense and copy cat apps.

3. I know the palm guy is now in Android but do you have to copy Project Ares (btw their interface is way better then App Inventor)

As you can see, i hate it, giving power to create applications is not the same with the power normal people gets in creating websites, in the web you dont have to download and install something (unless android would have this feature) and thus mobile users are committed into what they had downloaded, but on the web, users usually pass by a page then forget about it like nothing happens and on the web you can just bounce into a single page in the middle of the sitemap and you dont have to download/visit the whole site.

For example, your friend, far from you, found a cute page on the web, most of the time they would give you a link and you'll click on it and you'll view it (its done), in a mobile application when your found a cute activity on the app, they would give the market link/apk/QRCode to their friend, friend would download, wait, install, wait, open app, other friend would tell them where to see the activity. These process is disappointing when the other friend, who's interest so happen to be slightly different, found out that app she/he got from the other friend is not worth her time. While this still happens in the web but usually the user would just close the site within few seconds and they dont have to uninstall it.

Unless Android or other mobile OS dont behave like the web, too many apps in any market that have more useless apps then useful apps are not a good indicator. And kindly fix the GUI on Eclipse or create a new IDE for Android for developers/designers if Eclipse is not enough for the GUI stuff.

Sunday, July 11, 2010

Debugging locally with App Engine and Android

Senario
AppEngine is free, Android is free thus you think that developing for both of them is cheap and thus you start working on your backend and found out that you have to connect the AppEngine to Android, how could you enable this?

Introduction
If you're in mac, there is the AppEngine software but what it does is bind your AppEngine application to localhost thus you cant access localhost in Android coz Android has its own localhost, and if you access via your ip and port on Android it might not work.

What Do I Need
Terminal
Mac or Linux (If you guys can port this in Windows or it works in Windows, kindly drop a comment below)

On App Engine
On your terminal, get your IP
ifconfig | grep 192
If you're under the 192.168 IP then you can see your IP, copy this. In mac its the first 192.168.x.x. For our example we would use 192.168.1.101 and bind it to 8082
cd <your AppEngine Folder
dev_appserver.py -a 192.168.1.101 -p 8082 .


On Android
In you App you can now access 192.168.1.101:8082 and it shall return it from values from your AppEngine. This method works as long as your in the same network thus if there are more than one programmer both could access it.

You could use Open URL Tutorial to try it out :)

Tuesday, July 6, 2010

Access Internal classes in Android

So long before, i was blogging too much, then i stopped and told you guys i'll be doing more Android and Frontend, then i quit OpenRice and now back to doing Android as hobby.

Senario
Say you want to access some internal class in Android which are not public and you really want to use that feature, what do you do?

Notes
* This is on how to access non public classes thus are restricted classes which are not recommended, use this knowledge at your own risk and i'm NOT to be held responsible to any harm it might cause.
* This is quite advance and i hope to explain it as much as possible while keeping it simple.
* The following codes might not work as you/I expected it to work thus this is for reference only

Introduction
As i was trying to update my tutorial on Localization i was looking at how the locale setting was done and i found it at the LocalePicker.java under the onListItemClick function, if you try this code in your app you would realized that ActivityManagerNative and IActivityManager are internal classes. So how to use this piece of code?
IActivityManager am = ActivityManagerNative.getDefault();
Configuration config = am.getConfiguration();
Loc loc = mLocales[position];
config.locale = loc.locale;
final String language = loc.locale.getLanguage();
final String region = loc.locale.getCountry();
am.updateConfiguration(config);



What Do I Need
In Manafiest.xml
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />

Codes
DexFile  df = new DexFile(new File("/system/app/Settings.apk"));
String name = "com.android.settings.LocalePicker"; 
ClassLoader cl = getClassLoader();     
Class LocalePicker = df.loadClass(name, cl);
Class ActivityManagerNative = Class.forName("android.app.ActivityManagerNative");
Class IActivityManager = Class.forName("android.app.IActivityManager");

Method getDefault =  ActivityManagerNative.getMethod("getDefault", null);
Object am = IActivityManager.cast(getDefault.invoke(ActivityManagerNative, null));

Method getConfiguration =  am.getClass().getMethod("getConfiguration", null);

Configuration config = (Configuration) getConfiguration.invoke(am, null);
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
config.locale = locale;

Class[] args = new Class[1];
args[0] = Configuration.class;
Method updateConfiguration =  am.getClass().getMethod("updateConfiguration", args);
updateConfiguration.invoke(am, config);


Explanation
DexFile df = new DexFile(new File("/system/app/Settings.apk"));
You need to load the package from where the class is from
NOTE: The dex don't directly open or readed in this line but they're memory-mapped read-only by the VM.

String name = "com.android.settings.LocalePicker";
ClassLoader cl = getClassLoader();
Class LocalePicker = df.loadClass(name, cl);

Load the class where your target classes were imported.

Class ActivityManagerNative = Class.forName("android.app.ActivityManagerNative");
Class IActivityManager = Class.forName("android.app.IActivityManager");

Load the classes you want to use

Method getDefault = ActivityManagerNative.getMethod("getDefault", null);
To use a method you have to get the method first. http://developer.android.com/reference/java/lang/reflect/Method.html

Object am = IActivityManager.cast(getDefault.invoke(ActivityManagerNative, null));
Execute the getDefault method using the invoke class, and since it has a return of IActivityManager, cast the returned object.

Method getConfiguration = am.getClass().getMethod("getConfiguration", null);
Since am is an instance of IActivityManager we could use getClass() to reflect on its method.

Configuration config = (Configuration) getConfiguration.invoke(am, null);
Execute the getConfiguration method, you can see here we use the regular casting (Configuration), you could also use Configuration.Class.cast

ocale locale = new Locale(languageString);
Locale.setDefault(locale);
config.locale = locale;

Just set a new Locale configuration

Class[] args = new Class[1];
args[0] = Configuration.class;
Method updateConfiguration = am.getClass().getMethod("updateConfiguration", args);
updateConfiguration.invoke(am, config);

To reflect on a method with arguements you have to do it this way, the second argument is a list of Class type of the required arguments. Optionally you could refer to another approach found in Calling private methods in Android

Conclusion
Reflecting a class could be lead to unknown results, like this class would set System Wide language change and not application wise and thus executing would lead to your whole system being reconfigured on the language (your home screen would HANG after you change and click Home), this is a powerful tool thus "We great knowledge comes great responsibility" :)

References
Google Groups
ClassTest
LocalePicker.java
Calling private methods in Android
http://developer.android.com/reference/java/lang/reflect/Method.html

Sunday, July 4, 2010

Adobe Air Download for Android

Over at Droid-life an early version of Adobe Air was leaked, and the download links are there, the problem is that megaupload is blocked in some places on the globe including Hong Kong thus for our friends in Hong Kong, here are the links for Adobe Air in Rapidshare.com

http://rapidshare.com/files/404834594/AIR.apk.html
http://rapidshare.com/files/404838291/air_apps.zip.html

Friday, July 2, 2010

Birthday Gift to me by Google

Could be coincidence but I got an Official Android Froyo Update on my birthday. Thank you Google

Saturday, June 26, 2010

Theme Change and new video for newbie in Android

Change the theme of the site, just changed the font-size, background colors, font family and such. Really not android related. On my mobile programming google sites, i added a new video from GTUG that is really good if your really new to Android and Java. Check it out
http://sites.google.com/site/tutorialsformobileprogramming/android-videos

Thursday, June 24, 2010

Search For Android Tutorials

Replace the big ads on the top of the page with a more useful feature that lets you search android tutorials/articles. Hope this would help anyone in need. Goodnight (its 2am)

Wednesday, June 16, 2010

How to make your app faster in Android

Google IO is an amazing event where some sessions are really useful, one of which in Android this year is on "Writing zippy Android apps". This is essential if your doing android apps. Watch the whole video (most of the stuff applies to other technologies as well)

Saturday, May 29, 2010

Follow romain guy at twitter

I had been playing a lot games recently (blame Steam for it. ahahah) Anyway, over at twitter, Romain Guy from the Android team has been twitting good links/articles that would be visible in Android 2.2. Follow him for the Froyo goodness @romainguy

I love the new New HierarchyView feature, where you just give the psd to your creative guys. Now back to Steam (torchlight and soon warhammer40k) :)

Tuesday, May 4, 2010

Android 2.2 and the future

With Google IO coming in next next week, Android and the future looks bright. To recap what would could possibly see in Android 2.2

JIT Compiler - Speed boost for 2-3x (http://androidandme.com/2010/02/news/myriad-dalvik-turbo-boost-android-performance-2-3x/
Automatic App Update - Hate updating your app? This one is perfect, but it would be more perfect if they ask you if you want to update if a permission had be changed from the previous version to the current version
Flash 10.1 Support - Okay this excites me the most, why imagine playing the crazy flash games found on the web, which is super perfect for killing time
External Memory Install Apps - More space for apps is good for everyone
802.11n - Faster wireless internet, finally could make use of my n router

Others include
OpenGL ES 2.0 enhancements
Fixed problem with “crazy screen” / Resolution of cross multitouch
Activation of Color Trackball
Enable FM radio

The future
  • Dragon Point - An official fork of Android intended for Google TV
    - Important for the screen resolution, from mobile screen to TV screen
    - Android would be compiled to Intel based chipset
    - With the recent announcement of BumpTop, i want a Sony TV with Sony Eye with BumpTop navigation.
  • Android Tablet - Recent announcement from Google CEO
    - With HP cancels Slate, its gonna be huge for Android on the tablet space thus more market to explore
    - Tablet OS could be perfect for Netbook thus more market
  • Wishlist
    Better Market - Or at least better search on the market
    Paid Apps on more Countries
    Integration of Bondi specs
    Integrate VP8 Codec on every Android device (put an end to the video format war)
    Freaking stop Microsoft from getting Money from Android
    Android N2 with keyboard, HDMI output, Snapdragon 1.5GHz
    PS4 with Android

Friday, April 30, 2010

Tim Bray as Android Blog Editor, Google Sites and Mobile Contest

Tim Bray is now the new editor of this Android Developers’ Blog, exciting times for the Android Developers' blog, my wish is to further expand the knowledge on how to do certain things and on the side note build a better emulator where we could emulate consumers phone hardware. Let help and hope that Tim would bring android to the next level. More of this news on http://android-developers.blogspot.com/2010/04/more-blogginess.html

A Google Site? As i have switch job to being more on FrontEnd Programmer with Openrice.com, there im doing Android, CSS, Javascript, Flash, Bondi and a lot more. My love for Android and the mobile scene grows everyday. And one proof of that love a Google Site on Tutorials for Mobile Developers (Its super new)
http://sites.google.com/site/tutorialsformobileprogramming/android-tutorials, The android links are quite complete i suggest you guys to check it out.

Another proof is a site dedicated for developers around the world to get a chance to be the next big thing on mobile arena by wining contests that companies hosted, and that proof is http://www.mobileappcontests.com/

As other might notice, i havent been blogging lately, its because of the proof above and the rewriting of http://butiwanttowatchit.com/ from PHP to App Engine Python (http://www.niw2win.com/).

All Google? Nope as stated above i'm not working for them but how i wish (hope i wont fail again if i got another interview), its just im for open source, I love ubuntu, firefox, bondi widgets, cakephp, jquery and a lot more.

Hope the new services above would help my fellow developers :)

Tuesday, April 20, 2010

Change View Position in Android

After a long silence, im back with a new Android post, a problem i encounter recently. So you have a view, you want to change the location of the view how can you do that?

There are a lot of ways in dealing with this, you could use SurfaceView and add some Views on top of it, or if you think its hard to deal with SurfaceView then here is a solution.

This solution might not be the best solution but it does work, and it works if you if still need to cater the first batch of android phones that comes with 1.5,1.6.

yourView.layout(left,top,left+width (right), top+height(bottom)


I used in a custom view with animation where setFillAfter is not working properly, so i have to come out with a solution on where the last frame of the animation is the layout(l,t,r,b) new position.

Tuesday, April 6, 2010

Android developers in the Philippines

Are you a developer and your currently in the land of my birth, the Philippines, then head over to Globe's site to check out the new and exciting Android contest
http://site.globe.com.ph/android

Got this from my new blog
Mobile App Contests

Friday, April 2, 2010

To OpenRice, not to Google

April fool is done here on our side of the globe, and thus time to reveal the real company. I did resign from Razorfish for several reason, and the biggest reason is I wanted to focus more on Mobile and thus this is where OpenRice comes into play.

OpenRice is the biggest Restaurants Guide in HK, and is currently expanding in other SouthEast Asia region like the Philippines, Shenzhen China and Macau.

In OpenRice,i would deal with more Mobile and more of Frondend web, as my title would suggest, for other details cant discuss it but definitely would have more time to explore the mobile arena and would have more time to help other Android developers :)

Thursday, April 1, 2010

Will Work in Google

Great news, to the readers of this blog, i would be heading to Google to do Android stuff. Happy times ahead :)

One of the main role is to provide more communication with external programmers, this comes hand in hand with building more Tutorials, building tools for autogeneration of codes and helping you guys how to understand the documentations on Android dev.

This site will remain as is and would include some tutorials and how to that might be tackle on the tutorial site that is planned for you guys.

I would like to thank Razorfish Hong Kong for all the knowledge and experience they provided during my stay.

Sunday, March 21, 2010

Google TV and why its important

Last week Google, Intel, Sony and Logitech announced Google TV, while everyone seems to think that its just a stab at something like boxee box, the partnership has more than what meets the eye.

Google - for Google they want to put their android in much device as possible, they said this when they released the MIPS port of Andriod, now before MIPS gets big with android, Intel need to enter the picture, they need to enter now or else it would be like ARM in mobiles where is almost a monopoly, MIPS is already huge but we will be seeing a transformation on your home appliances making them smarter then before. Now this move is huge for Andriod for right now it doesn't have an official x86 or x64 chipset for the OS. Android as what most people expect would be the wheel to Google's ads platform, if you have people searching then you have ads to show.

Intel - they said they want to enter the mobile scene, they made Moblin out of these desire and later on added Nokia on their track that made the world's most selling phone company to dump ARM on some of its phone like N900 then later on combine Meamo and Moblin to make MeeGo. Now it seems they can't force Google to build one for mobile device and they need to get that OS running on their chips because like Google's Ads, Intel cares so much on putting their chips on every possible device. And technically Andriod having an Intel chipset for Google TV could be easily be ported to mobiles.

Sony - the supposed original maker of Nexus One is once again approach by Google, its not their first time they collaborate, remember Google chrome to be the default browser in every vaio, Sony is huge worldwide and it has some interesting products but recently they can't strike a good selling product and they seems to have the need to have one and they do know that Andriod and Internet based tv-setup boxes are becoming huge in US, therefore if this product succeeded would be their way of surviving

Logitech - they are so well known for their computer products like keyboard and mouse. Having them here would mean that they would create remote controls for Google TV, but that's not the fun part, the fun part is that Logitech's device would have drivers for Android and if Logitech is kind enough it would mean official drivers for Linux on their products.

Another good thing that would come out of this partnership is that Andriod is getting out of Mobile device screen size and getting into a screen that varies so much in inches and if they did a good job here then expect android to live in your PC anytime and with Intel and their 90%+ x86 or x64 share on desktop, Android would be huge.

The bad impact is that it will further fragment the Android market share and harder for developers to develop programs.

Sunday, March 14, 2010

Play MediaPlayer with Authentication on Android

I was back to the Android lang with the free Nexus One from Google, and had a project in mind that involves MediaPlayer and for which here is how i did it.

private void playAudio(String mediaUrl) {
  try {
    URLConnection cn = new URL(mediaUrl).openConnection();
    cn.setRequestProperty("Your Header Name", "Your Header Value");
    InputStream is = cn.getInputStream();
    // create file to store audio
    File mediaFile = new File(this.getCacheDir(),"mediafile");
    FileOutputStream fos = new FileOutputStream(mediaFile);   
    byte buf[] = new byte[16 * 1024];
    // write to file until complete
    do {
      int numread = is.read(buf);   
      if (numread <= 0)  
        break;
      fos.write(buf, 0, numread);
    } while (true);
    fos.flush();
    fos.close();
    MediaPlayer mp = new MediaPlayer();
    // create listener to tidy up after playback complete
    MediaPlayer.OnCompletionListener listener = new MediaPlayer.OnCompletionListener(){
      public void onCompletion(MediaPlayer mp) {
        // free up media player
        mp.release();
        Log.i("MediaPlayer.OnCompletionListener", "MediaPlayer Released");
      }
    };

    mp.setOnCompletionListener(listener);
    FileInputStream fis = new FileInputStream(mediaFile);
    mp.setDataSource(fis.getFD());
    mp.prepare();
    mp.start();
  } catch (Exception e) {
    e.printStackTrace();
  }
}


Explanation
First up this code came from http://stackoverflow.com/questions/1650983/server-side-aac-audio-with-android where it was the answer to a different question.

URLConnection cn = new URL(mediaUrl).openConnection();
cn.setRequestProperty("Your Header Name", "Your Header Value");

This is the core part and probably the only explanation beside the concept of the code that ill do. On here you create a URLConnection on where you can specify the request(headers) Property, depending on how you made the authentication on your server (say like GData) you can pass any headers related values.

Now on the concept, what the code does is like what it had said in stackoverflow, it downloads the music, outputs it to a FileOutputStream under the mediaFile File, where then we get to stream it to the FileInputStream which then we use as our data source on our MediaPlayer.

Hope this helps :)