Draw beautiful diagram effortlessly on ipad. Click here to know more..

Sunday, January 15, 2012

Drawing and erasing using touch on Android

Drawing/Erasing using touch is a common feature in many mobile phone/tablet based apps. Writing code for this feature is pretty simple for android. Here are steps to do that:
  • add a custom view on which you will draw.
  • process touch event on view.
  • on touch event, record points where touch event occurred.
  • in onDraw method, draw points that were recorded.

Adding a custom view:

We will derive a class from View class for implementing drawing canvas. And we will add this to UI tree. To add this to UITree, create a LinearLayout in which the custom view will be added. The LinearLayout is declared in layout xml as:
  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="horizontal"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      android:id="@+id/drawPanel">
    </LinearLayout>
and from the code, add the custom view to this LinearLayout as:
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        LinearLayout ll = (LinearLayout)findViewById(R.id.drawPanel);
        DrawPanel drawingPanel = new DrawPanel(getApplicationContext());
        ll.addView(drawingPanel);
    }
This code finds the LinearLayout object which was defined in XML and then adds an object of DrawPanel to this. The DrawPanel is the custom View class which is being used for drawing. Here is the implementation of DrawPanel


public class DrawPanel extends View { 
public DrawPanel(Context context) {
  super(context);
  points = new ArrayList();
  strokes = new ArrayList();
  paint = createPaint(Color.GREEN, 8);
 }

 @Override
 public void onDraw(Canvas c){
  super.onDraw(c);
  this.setBackgroundColor(Color.WHITE);
  for(Object obj: strokes){
   drawStroke((ArrayList)obj, c);
  }
  
  drawStroke(points, c);
 }
 
 @Override
 public boolean onTouchEvent(MotionEvent event){
  if(event.getActionMasked() == MotionEvent.ACTION_MOVE){
   points.add(new Point((int)event.getX(), (int)event.getY()));
   invalidate();
  }
  
  if(event.getActionMasked() == MotionEvent.ACTION_UP){
   this.strokes.add(points);
   points = new ArrayList();
  }
  
  return true;
 }
 
 private void drawStroke(ArrayList stroke, Canvas c){
  if (stroke.size() > 0) {
   Point p0 = (Point)stroke.get(0);
   for (int i = 1; i < stroke.size(); i++) {
    Point p1 = (Point)stroke.get(i);
    c.drawLine(p0.x, p0.y, p1.x, p1.y, paint);
    p0 = p1;
   }
  }
 }
 
 private Paint createPaint(int color, float width){
  Paint temp = new Paint();
  temp.setStyle(Paint.Style.STROKE);
  temp.setAntiAlias(true);
  temp.setColor(color);
  temp.setStrokeWidth(width);
  temp.setStrokeCap(Cap.ROUND);
  
  return temp;
 }
 
 private Paint paint;
 private ArrayList points;
 private ArrayList strokes;
}

The above code is for drawing. With a small tweak, erasing can be implemented. While erasing, set the paint color as that of background, that's it!! 

The above code is used in Scratchpad, a drawing app for Android tablets.

Tuesday, January 10, 2012

My first android app: learning+coding+publishing in 5 days


Hey! don't be surprised.  This is not a game like "Angry Birds". Typically, 5 days are not sufficient for a beginner to create a descent app. But my app is not just a "Hello World" app. This is Scratchpad: a simple drawing app. This can be used mostly by kids to draw/erase with touch and can also share the drawing using emails or any other image sharing app. The Scratchpad also has a feature of smoothing the hand-drawn curve which makes it little different from other similar apps.

Here is how this was started: During the new year vacation, I wanted to learn about  Android app development. I got 5 days: 28th Dec to 1st Jan. On the first day, I spent few hours to read about the Android app fundamentals on the Android developer website. I already knew Java, so I did not have to learn a new programing language. After reading the fundamentals, I downloaded few sample projects from internet and started running them. On the 2nd days, I was going through the source code of the samples and running them on emulator. There were many samples to run, so I was not doing any modification to code. I was quickly running those code. At the end of second day, I got confidence that I can now write an app. Then got the idea of a drawing app and then started on this.

I started on development of the drawing app on the evening of second day. Then suddenly I thought that let me release this app on 1st of Jan and make this new year very special. I had only 3 days left (including 1st Jan), I was not sure that I will be able to complete or not.

By the end of 3rd day, I had most of the features working. I was feeling much more confident. But icon work was still not done. Here is the list of things that that I completed:-
  • Drawing using touch
  • Erasing
  • Selecting color
  • Setting pen width
  • Export the drawing as png to Pictures folder, so that it can be viewed in Gallery app.
  • Share the drawing using email or any other sharing app that is installed on device.

I had to struggle a bit for color picker dialog. I could not find any standard Android widget for this. I searched on internet, there were many samples available. I tried few of them and picked one.

On the 4th day morning, I was feeling much more confident. Now I was thinking to add a feature that can differentiate the Scratchpad from other similar apps. So I decided to add a feature of curve smoothing. I already had C++ curve fitting code. Porting the C++ code to Java could take much time. I wanted to wrap-up by the day. So tried java native interface using NDK. Using NDK was straight forward. I integrated the C++ code within few hours.

By now, I was done with all features that I wanted. Now it was time to work upon icons. I searched for free icons on internet and picked some free icons. But I had to edit almost all icons in GIMP.

Now it was 4th day evening. Everything done!! I was very happy!! Now started testing and found a bug!! The bug was in the C++ curve fitting code. It was silently crashing the app. I had no idea what was wrong. Tried the debugger that comes with NDK, but it did not work properly. The NDK build was striping-off the debug symbol even if it was given debug flag. I worked around this by copying the shared object file from obj folder to libs manually after the build. But it did not help. The debugger was reading the debug symbol incorrectly. I was not able to step or print the variable values. However I was able to break the debugger at given function. Now I had two options:- give more time to fix the debugging or create a standalone Linux application or standard Java application and use and test the curve fitting code there. But these options were to take much time. Then I worked around the issue by different way. The issue used to reproduce if the number of points to smooth were very high. If the number of points are very high, then not calling the smoothing was temporary solution. In a typical usage of the app, it was not reproing.

On the last day (1st Jan), I created developer account, signed my app, created screenshots and uploaded my app. After two or three hours, it was available on the Android market.
While publishing the app, I discovered that Indian developer can not publish paid app on android market. I was disappointed by this. Although the Scratchpad was free, I have plan for my next paid app. Now I am considering iOS platform for my future paid app.

On the next day I was very disappointed to see that there were no downloads of this app. Then I shared the the app on reddit (/r/androidapps)  and then the app started getting downloaded. As of now there are 30 downloads of this app.

I wanted to replace one of the screenshot of the app on the android market. It seems there is some bug. From the web interface, it lets to upload/replace screenshot but actually it is not updating.

One more thing that I did not mention yet. The experience of working on emulator is very bad. It is too slow to work on. I was mostly working on a tablet (Asus EEE Pad Transformer). My code was crashing on emulator with older version of android (older then Honeycomb). Because of time constraint and slow emulator experience, I did not get much time to debug the issue and removed the support for older android versions. The Scratchpad works for Honeycomb and newer Android version. I guess, the Scratchpad download would have been more if it supported older version.
Here is android market link to Scratchpad: https://market.android.com/details?id=com.avabodh.scratchpad