Constraints of multiple layouts listview for android

Programming listview with multiple layout is very easy with android built in method. It is very useful but be careful with the constraints. I will like to introduce about the constraints of list adapter with multiple view types.

 

(1) getItemViewType(int position) method

You must override getItemViewType. Let’s say you have two type of layouts, seperator and text layouts, you have to returned in this way.

@Override
public int getItemViewType(int position) {
    if(mList.get(position).type == TYPE_SEPERATOR){
        return 0; // seperator layout
    }
    return 1;  // text layout
} 

 

(2) getItemViewType index begin with 0

Continue reading

Advertisements

Setup egit for eclipse ADT by install new software

I spent almost half an hour to set it up. The whole setup process was spending less then 5 minutes and the rest of the time almost spent in googling and blogging.

I am going to guide you a straight forward way to setup it all up.

Install new software

  1. On menu bar, go to Help -> Install New Software…
  2. Type http://download.eclipse.org/egit/updates into Works with and press enter key. (Don’t need to press Add… button)
  3. Then, you will see Eclipse Git team provider. Check Eclipse Git.

Done ?!

Yes! It is done! You can check it by About ADT.

Show Git on menu bar (Optional)

You can setup git on your menu bar by a few steps

Continue reading

Simple guide to ExecutorService Android

ExecutorService is almost same as ThreadPoolExecutor, it allows you to carry out multiple background thread in sequentially.

What can ExecutorService do? Do you know that powerful AsyncTask method is only allows to be executed one time in single activity. If you execute AsyncTask more then one time in single activity, you will get the errors.

So it is where ExecutorService comes, it help you handle multiple background task which AsyncTask cannot be done.

Try it out!!

It is always easy to understand if you get something work first. 
First, prepare server script. 
<?php  
 echo "hello! I am server.";
?>
Remember the url of your server. Then, copy following android code and replace the url to your own and give permission to internet.
package com.example.apps1;
 
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
 
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.Toast;
 
public class MainActivity extends Activity {
 
 private Button mButton;
 private ExecutorService pool;
  
 public static final String URL = "http://path_to_server/";
  
 private static final String TAG = MainActivity.class.getName();
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                
        
        mButton = new Button(this);
        mButton.setText("Press");
         
        addContentView(mButton, new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
          
        pool = Executors.newSingleThreadExecutor();
         
        mButton.setOnClickListener(mClickListener);
    }
     
    private View.OnClickListener mClickListener = new View.OnClickListener(){
 
  @Override
  public void onClick(View v) {
   pool.execute(new NetworkService());   
  }     
    };    
     
     
    private class NetworkService implements Runnable {
     private Handler mHandler;
     public NetworkService(){
      mHandler = new Handler(Looper.getMainLooper()){
        
       @Override
       public void handleMessage(Message inputMessage){
         
        String msg = (String) inputMessage.obj;        
        Toast.makeText(getApplicationContext(), ""+msg, Toast.LENGTH_SHORT).show();        
       }       
      };
     }
      
  @Override
  public void run() {
   String recv = HttpRequest(URL);
   sendMessage(1, recv);
  }
   
  public void sendMessage(int what, String msg){
   Message message = mHandler.obtainMessage(what , msg); 
   message.sendToTarget();
  }
      
    }
     
    // Doing all Networking task, if failed to get message from server, it will return null  
 // 
 public String HttpRequest(String url) {
       
   DefaultHttpClient client = new DefaultHttpClient();
   HttpResponse response = null;
      
   try{          
    HttpGet httpGet = new HttpGet(url);     
    response = client.execute(httpGet);     
            
    return EntityUtils.toString(response.getEntity());
 
   }catch(ClientProtocolException e){
    Log.e(TAG,"ClientProtocolException : "+e);
   }catch(IOException e){
    Log.e(TAG,"IOException : "+e);
   }      
 
   return null;
  }
}
Press the button and toast will show you the message from server.

Explanation

ExecutorService can be instanced in few different way.

  1. Executors.newSingleThreadExecutor();
  2. Executors.newFixedThreadPool(10); 
  3. Executors.newScheduledThreadPool(10);

Based on how ExecutorService is instanced, ExecutorService will be working in different way. For more detail please checking Executors API. In this guide, I am using newSingleThreadExecutor, it only allows one task in the same time.

NetworkService is implemented with Runnable. NetworkService is almost same as AsyncTask, contains UI thread callback method, doInBackground method.

In this case, same method of AsnycTask and NetworkService

  • doInBackground == run
  • onPostExecute == handleMessage
private class NetworkService implements Runnable {
 private Handler mHandler;
 public NetworkService(){
   
  // Handler looper constructor to declare this handler
  // is going to link to UI Thread 
  mHandler = new Handler(Looper.getMainLooper()){
    
   // handleMessage method is callback of background work.
   // All the tasks in handleMessage will be pass to UI thread
   //
   // This method is same as AsyncTask.onPostExecute        
   @Override
   public void handleMessage(Message inputMessage){
     
    String msg = (String) inputMessage.obj;        
    Toast.makeText(getApplicationContext(), ""+msg, Toast.LENGTH_SHORT).show();        
   }       
  };
 }
  
 // Runnable.run method doing all tasks in background
 // It is same as AsyncTask.doInBackground
 @Override
 public void run() {
  String recv = HttpRequest(URL);
   
  // Get the result from HttpRequest and past it to handler.
  sendMessage(1, recv);
 }
  
 public void sendMessage(int what, String msg){
  Message message = mHandler.obtainMessage(what , msg); 
  message.sendToTarget();
 }
  
}
Every time user press the button, NetworkService will be created and added to background’s pool. If there is no task queue in front the NetworkService task, it will be executed.
pool.execute(new NetworkService());   
Background task is not an easy task. There are much more work then the sample code on above such as shutdown or pause the ExecutorService. What I have explain in this article is to get you works on your apps quickly. 

End

Hope this article help you in coding. Thank you for reading.

Getting started with Developing Bluetooth 4.0 LE and Android with BLE112 Bluetooth module

If your objective is asking BLE112 to say “helloworld” to Android or any other smart phone in faster, quick and simple way. You are on the right way. I am going to guide you how to get BLE112 to connect to your Android, Iphone or any others smart phone.

Materials

What you need is

  1. Bluetooth module ( BLE112 )  USD$50
    http://www.inmojo.com/store/jeff-rowberg/item/ble112-bluetooth-low-energy-breakout/
  2. CC Debugger USD$ 49
    http://www.ti.com/tool/cc-debugger 
  3. Android which adaptable to Bluetooth 4.0

And the software you need to installed

  1. Bluetooth Smart Software and SDK ( Provided by bluegiga ) 
    http://www.bluegiga.com/en-US/products/bluetooth-4.0-modules/ble112-bluetooth–smart-module/documentation/
Bluegiga provide the SDK for free, but you have to register a new account to download it.

Reason why I choose BLE112 breakout board. BLE112 embed with antenna and bluetooth built in chip (Texas Instrument cc2540). It means you can begin your development with ble112 in a very cheap price around USD$12 to $16. However, bluegiga do not provide a nice pin leg and you need to soldering it to board in order to connect it to cc debugger. Here’s the reason why I choose jeff-rowberg breakout board. On jeff-rowberg site, it provide two type of board, one is ble112 embed and one is without embed. It save my time to design the breakout board and soldering ble112.

Preparation

Download the Bluetooth Smart software and SDK and install it by follow the instruction.

After you have successfully installed Bluetooth SDK, you are almost there. Connect cc debugger and ble112. To easy my developing, I soldering pin socket to ble112. It is optional for you either soldering pin socket or not.

There are three things needed to connect.

  1. usb to cc debugger
  2. cc debugger to ble112
  3. ble112 to 3.3V power supply
Pinout is written on board, so you should able to find GND and 3V3
Newbie usually think that debugger provide power to module, but it is WRONG.
Debugger do not provide power to module, you have to provide external power to module. Here’s the why number 3 comes.
After you have setup all the things, let’s begin to debug the ble112.

Debug

Go to Bluetooth Smart SDK directory -> example -> find_me directory. Run project.bgproj and you will see the following window.
Click Refresh button to detect debugger. Then, click Info to detect ble112. The you should see that cc-debugger led turn red to green and the message show in dialog. If led already turn green light, then it should be okay. Green light means that chip have been successfully detected.
If “No chip detected” messages is showed and LED is red, it means that cc debugger unable to detect the ble112. There are 3 things you needs to do.
  1. Make sure BLE112’s power is supplied by external power supply but not from debugger.
  2. Make sure CC debugger pin is correctly connected to ble112.
  3. Long press the cc debugger reset button.
Make sure that File point to correct directory “find_me” and “project.bgproj”.
Then, click Update to begin debug.
If you see the following messages, it means you have successfully debug the chip. 

Testing with Android

Go to bluetooth settings and enable Bluetooth. Click “Search for devices”.
If you see “Bluegiga Find Me”, it means your bluetooth have successfully connected to Android. If you can’t see it. Most probably your android device is not adaptable to Bluetooth 4.0, test it with another device which adaptable to Bluetooth 4.0

End

Here’s the end of the blog. Hope you are successfully to see the messages. On next section, I will begin to explain about more detail on what is going with “Bluegiga Find me” and how BLE112 interact with microcontroller.
Hope you will continue with it. Thank you for your reading.

How to inject javascript in android webview like chrome javascript console

If you used to inject javascript to test your website on chrome. You can do so on android webview.

To achieve it, you need to add internet permission on your AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

Then, on your main_activity_layout.xml , add webview

<WebView android:id="@+id/web"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Next, on your MainActivity.java, instance webView and add following code.

final WebView webView = (WebView)findViewById(R.id.web);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
  
  public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {     
   Log.e("browser",description);
   dialog.dismiss();
   }
 
    @Override
    public void onPageFinished(WebView view, String url) {
        // do your javascript injection here, remember "javascript:" is needed to recognize this code is javascript
        webView.loadUrl("javascript:document.write('hello')"); 
    }
     
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
     // this method is needed to ignore SSL certificate errors if you are visiting https website 
        handler.proceed(); 
    }
 
});
 
webView.loadUrl("https://your_sites.com");  

Javascript is disabled in default, you need to enable it by calling setJavascriptEnabled method.

Javascript needed to be added after the page is finished loaded, otherwise javascript will be debug before the page loaded.

Simple Custom Dialog for Android

Android developers have provided us based on how to create a custom dialog by using alertdialog.builder method. If you are interesting with it, here’s the link. http://developer.android.com/guide/topics/ui/dialogs.html

I am going to shows another way instead of using alertdialog.builder. What is the benefit of this method is you can update the content of dialog view dynamically and directly.

If you are thinking changing the content of dialog when the button is pressed without closing dialog. You might give a try on this method.

First, create the layout for custom dialog

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <TextView
        android:id="@+id/dialog_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="this is custom dialog"/>
    
    <LinearLayout 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/dialog_positive_button"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="0.5"
            android:text="positive"/>
        <Button
            android:id="@+id/dialog_negative_button"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="0.5"
            android:text="negative"/>
            
    


Then, create the custom dialog class

class SimpleCustomDialog extends AlertDialog{
 
 TextView text;
 
 SimpleCustomDialog(Context ctx){
  super(ctx);
  setTitle("Custom Dialog");
  
  LayoutInflater inflater = getLayoutInflater();
  View view = inflater.inflate(R.layout.alertdialog_layout, null);
  
  text = (TextView)view.findViewById(R.id.dialog_text);
  text.setText("this is custom dialog");
  
  Button positiveButton = (Button)view.findViewById(R.id.dialog_positive_button);
  Button negativeButton = (Button)view.findViewById(R.id.dialog_negative_button);
  
  positiveButton.setOnClickListener(new PositiveButtonListener());
  negativeButton.setOnClickListener(new NegativeButtonListener());
  setView(view);
 }
 
 class PositiveButtonListener implements View.OnClickListener{
  @Override
  public void onClick(View view) {
   text.setText("Button clicked");  
  }   
 }

 class NegativeButtonListener implements View.OnClickListener{
  @Override
  public void onClick(View view) {    
   // dialog wouldn't dismiss itself, you have to call dismiss method 
   //dismiss dialog
   SimpleCustomDialog.this.dismiss();  
  }   
 }
 
}

finally call show method to show dialog

SimpleCustomDialog mDialog = new SimpleCustomDialog(this);
mDialog.show();

If you want to dismiss the dialog, just call dismiss method.

Hope this article helps you. Thank your for reading.

Simple Sync Apps

About Download

Click here to download. The zip file contains 2 projects and 1 php file.

Introduction

I begin to learn programming is still half of a years ago and I begin to write this application is about one months ago. Begin from 0 knowledge to network and server. So I couldn’t make sure that I have wrote a very perfect program. But, this application do exactly what I need for that is synchronizing between android and desktop. 
It is how it’s look like. Check it out with the following video.

How it’s work

sync_pic1Picture above shows how the data is transferred. Database server is a bridge to allow data move from android to desktop and move from desktop to android. That’s all, simple right!
Of course that’s other way such as cloud computing or others. Based on my knowledge, this is easier way I know.

Develop Environment

My develop environment is Java JDK version 1.7.0_13, Eclipse SDK (Juno version 4.2.1), XAMPP 1.8.1, MySQL Connector/J 5.1.23, android 4.2
Because every software I used to develop this application is open-source, I spent a zero cost on this project.

Program Flow Chart

sync_pic2 Flow chart beside shows how data is passing through between android and desktop.
When user press a button on UI thread to ask android read what desktop have written, android will begin access to MySQL server.
In server side, 2 php files ( update database and read database php files) is created and located at htdocs. After android will success to access into server, then android will begin searching the php files requested (either update or read php files) through HTTP protocol.

Request ask for read database php file to work. When read database php file is executed, php file will begin it’s work by log in to database and retrieve the data requested that what desktop have written into database. After, php get the data it wants from database, it will pass it again to android and android get the data and put it on UI thread to show user what data have retrieved from database.
If the desktop ask for what android have written, it (desktop) will do exactly same things as what android did. desktop will going into database adapter request for data it wants. Then database adapter will log in to database server through Java-MySQL connector and search for what android have written into database. After database adapter get what their want, it will pass the data to desktop and desktop will put it on screen to show user what data it ( desktop ) got.

Source Code

  • mysqlAndroid is an android project. Inside this project contains three java source code. (JsonParser, JsonPost and MainThread)
  • JsonParser.java contains HttpGet method. There is no input data to url, only retrieve data from php file.
  • JsonPost.java contains HttpPost method. This method allow data post into php file.
  • MainThread.java is a UI thread work that called the button or textView method allow user talk with machine.
  • mysqlDesktop is an java Swing project. Inside this project contains three java source code and one external jar that is DatabaseAdapter.java, jConnector.java and MainFrame.java and mysql-java Connector.
  • jConnector.java contains the source code that allow java project connect to MySQL database.
  • DatabaseAdapter.java used to make database work getting easier to carry out.
  • MainFrame.java is a source code allow user to talk with device through window form

Simple notepad for android

My develop environment is jdk1.7 , android 4.2, and eclipse 4.2.1 (Juno)

It’s the first android application I created. Precisely I creates it referring to the sample that android provided in android SDK and the notepad lesson that android developers provided. For more detail about notepad lesson, here’s the link.

Here’s how it looks like.
Left side is the note list and the right side is the note editor
It’s not really difficult to write this program if you have certain experienced to android apps program. Basically what I have used on this program mostly is fundamentally things like intent, SQLite database, options menu, list activity and of course life-cycle. If you are already tried the notepad exercise that I mentioned above basically you can understand what I’m writing about. 

If you are interest with my project click here to download.

I’m going to show what I have written on this project.

Here’s the java code for note list

package com.example.note;

import android.os.Bundle;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.AdapterContextMenuInfo;

public class NoteList extends ListActivity {


private static final int DELETE_ID = Menu.FIRST;
private int mNoteNumber = 1;

private NotesDbAdapter mDbHelper;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notelist);
mDbHelper = new NotesDbAdapter (this);
mDbHelper.open();
fillData();
registerForContextMenu(getListView());
Button addnote = (Button)findViewById(R.id.addnotebutton);
addnote.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createNote();
}
});

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.notelist_menu, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_about:

AlertDialog.Builder dialog = new AlertDialog.Builder(NoteList.this);
dialog.setTitle("About");
dialog.setMessage("Hello! I'm Heng, the creator of this application. This application is created based on learning." +
" Used it on trading or any others activity that is related to business is strictly forbidden."
+"If there is any bug is found please freely e-mail me. "+
"\n\tedisonthk@gmail.com"
);
dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();

}
});
dialog.show();
return true;

default:
return super.onOptionsItemSelected(item);
}
}

private void createNote() {
Intent i = new Intent(this, NoteEdit.class);
startActivityForResult(i, ACTIVITY_CREATE);
}

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Intent i = new Intent(this, NoteEdit.class);
i.putExtra(NotesDbAdapter.KEY_ROWID, id);
startActivityForResult(i, ACTIVITY_EDIT);
}

private void fillData() {
// Get all of the notes from the database and create the item list
Cursor notesCursor = mDbHelper.fetchAllNotes();
startManagingCursor(notesCursor);


String[] from = new String[] { NotesDbAdapter.KEY_TITLE ,NotesDbAdapter.KEY_DATE};
int[] to = new int[] { R.id.text1 ,R.id.date_row};

// Now create an array adapter and set it to display using our row
SimpleCursorAdapter notes =
new SimpleCursorAdapter(this, R.layout.notes_row, notesCursor, from, to);
setListAdapter(notes);
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}

@Override
public boolean onContextItemSelected(MenuItem item) {
switch(item.getItemId()) {
case DELETE_ID:
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
mDbHelper.deleteNote(info.id);
fillData();
return true;
}
return super.onContextItemSelected(item);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
fillData();
}

}

Here’s the XML code for note list


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/notelist">

<TextView
android:id="@+id/textViewTop"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:paddingBottom="35dp" />

<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/btmLayout"
android:layout_below="@+id/textViewTop"
android:background="#FFF9C8"
android:divider="#D3D3D3"
android:dividerHeight="1sp"
android:footerDividersEnabled="true" />

<LinearLayout
android:id="@+id/btmLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:layout_alignParentBottom="true"
android:layout_marginBottom="3dp"
android:layout_marginTop="10dp">

<Button
android:id="@+id/addnotebutton"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:background="@drawable/create_note" />





The name written on background for instance notelist and create_note is the png image files. You can download it at the top of this blog.

Here’s the XML code for list row


<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10sp"
android:textSize="25sp"
android:hint="@string/no_title"
android:id="@+id/text1"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize = "25sp"
android:id="@+id/date_row"
android:layout_alignParentRight="true"
android:layout_marginRight="10sp"/>

Here’s the java code for note edit

package com.example.note;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class NoteEdit extends Activity {
public static int numTitle = 1;
public static String curDate = "";
public static String curText = "";
private EditText mTitleText;
private EditText mBodyText;
private TextView mDateText;
private Long mRowId;

private Cursor note;

private NotesDbAdapter mDbHelper;

public static class LineEditText extends EditText{
// we need this constructor for LayoutInflater
public LineEditText(Context context, AttributeSet attrs) {
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(Color.BLUE);
}

private Rect mRect;
private Paint mPaint;

@Override
protected void onDraw(Canvas canvas) {

int height = getHeight();
int line_height = getLineHeight();

int count = height / line_height;

if (getLineCount() > count)
count = getLineCount();

Rect r = mRect;
Paint paint = mPaint;
int baseline = getLineBounds(0, r);

for (int i = 0; i < count; i++) {

canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
baseline += getLineHeight();

super.onDraw(canvas);
}

}


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mDbHelper = new NotesDbAdapter(this);
mDbHelper.open();

setContentView(R.layout.note_edit);
setTitle(R.string.app_name);

mTitleText = (EditText) findViewById(R.id.title);
mBodyText = (EditText) findViewById(R.id.body);
mDateText = (TextView) findViewById(R.id.notelist_date);

long msTime = System.currentTimeMillis();
Date curDateTime = new Date(msTime);

SimpleDateFormat formatter = new SimpleDateFormat("d'/'M'/'y");
curDate = formatter.format(curDateTime);

mDateText.setText(""+curDate);


mRowId = (savedInstanceState == null) ? null :
(Long) savedInstanceState.getSerializable(NotesDbAdapter.KEY_ROWID);
if (mRowId == null) {
Bundle extras = getIntent().getExtras();
mRowId = extras != null ? extras.getLong(NotesDbAdapter.KEY_ROWID)
: null;
}

populateFields();

}




@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveState();
outState.putSerializable(NotesDbAdapter.KEY_ROWID, mRowId);
}

@Override
protected void onPause() {
super.onPause();
saveState();
}

@Override
protected void onResume() {
super.onResume();
populateFields();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.noteedit_menu, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_about:

/* Here is the introduce about myself */
AlertDialog.Builder dialog = new AlertDialog.Builder(NoteEdit.this);
dialog.setTitle("About");
dialog.setMessage("Hello! I'm Heng, the creator of this application. This application is created for learning." +
" Using it on trading or any others activity that is related to business is strictly forbidden."
+"If there is any bug is found please freely e-mail me. "+
"\n\tedisonthk@gmail.com"
);
dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();

}
});
dialog.show();
return true;
case R.id.menu_delete:
if(note != null){
note.close();
note = null;
}
if(mRowId != null){
mDbHelper.deleteNote(mRowId);
}
finish();

return true;
case R.id.menu_save:
saveState();
finish();
default:
return super.onOptionsItemSelected(item);
}
}

private void saveState() {
String title = mTitleText.getText().toString();
String body = mBodyText.getText().toString();

if(mRowId == null){
mDbHelper.createNote(title, body, curDate);
}else{
mDbHelper.updateNote(mRowId, title, body, curDate);
}
}


private void populateFields() {
if (mRowId != null) {
note = mDbHelper.fetchNote(mRowId);
startManagingCursor(note);
mTitleText.setText(note.getString(
note.getColumnIndexOrThrow(NotesDbAdapter.KEY_TITLE)));
mBodyText.setText(note.getString(
note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY)));
curText = note.getString(
note.getColumnIndexOrThrow(NotesDbAdapter.KEY_BODY));
}
}
}

Here’s the XML code for note edit


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFF9C8">

<RelativeLayout
android:id="@+id/toplayout"
android:background="@drawable/notetop"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:paddingBottom="5dp"
android:paddingLeft="5dp"
android:paddingTop="5dp" >

<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="@string/title"
android:id="@+id/title_text1" />
<EditText android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:hint="@string/no_title"
android:layout_toRightOf="@+id/title_text1"
android:background="@android:color/transparent"
android:layout_marginLeft="5dp"
android:singleLine="true"
android:imeOptions="actionNext"/>
<TextView
android:id="@+id/notelist_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:paddingRight="10sp"
android:textSize="18sp" />


<view
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/body"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toplayout"
class="com.example.note.NoteEdit$LineEditText"
android:background="@android:color/transparent"
android:capitalize="sentences"
android:fadingEdge="vertical"
android:gravity="top"
android:padding="5dp"
android:scrollbars="vertical"
android:textSize="22sp" />


Here’s the java code for note adapters that provided by android developers. It’s almost same but I did some edit on it that I added the one more parameter for date.

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

/**
* Simple notes database access helper class. Defines the basic CRUD operations
* for the notepad example, and gives the ability to list all notes as well as
* retrieve or modify a specific note.
*
* This has been improved from the first version of this tutorial through the
* addition of better error handling and also using returning a Cursor instead
* of using a collection of inner classes (which is less scalable and not
* recommended).
*/

/* It is not original code that notepad exercise provided.
*
* I did some edit on this code by adding date parameter on it.
*/

public class NotesDbAdapter {

public static final String KEY_TITLE = "title";
public static final String KEY_DATE = "date";
public static final String KEY_BODY = "body";
public static final String KEY_ROWID = "_id";

private static final String TAG = "NotesDbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;

/**
* Database creation sql statement
*/
private static final String DATABASE_CREATE =
"create table notes (_id integer primary key autoincrement, "
+ "title text not null, body text not null, date text not null);";

private static final String DATABASE_NAME = "data";
private static final String DATABASE_TABLE = "notes";
private static final int DATABASE_VERSION = 2;

private final Context mCtx;

private static class DatabaseHelper extends SQLiteOpenHelper {

DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

@Override
public void onCreate(SQLiteDatabase db) {

db.execSQL(DATABASE_CREATE);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS notes");
onCreate(db);
}
}

/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* @param ctx the Context within which to work
*/
public NotesDbAdapter(Context ctx) {
this.mCtx = ctx;
}

/**
* Open the notes database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* @return this (self reference, allowing this to be chained in an
* initialization call)
* @throws SQLException if the database could be neither opened or created
*/
public NotesDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}

public void close() {
mDbHelper.close();
}


/**
* Create a new note using the title and body provided. If the note is
* successfully created return the new rowId for that note, otherwise return
* a -1 to indicate failure.
*
* @param title the title of the note
* @param body the body of the note
* @return rowId or -1 if failed
*/
public long createNote(String title, String body, String date) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_TITLE, title);
initialValues.put(KEY_BODY, body);
initialValues.put(KEY_DATE, date);

return mDb.insert(DATABASE_TABLE, null, initialValues);
}

/**
* Delete the note with the given rowId
*
* @param rowId id of note to delete
* @return true if deleted, false otherwise
*/
public boolean deleteNote(long rowId) {

return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}

/**
* Return a Cursor over the list of all notes in the database
*
* @return Cursor over all notes
*/
public Cursor fetchAllNotes() {

return mDb.query(DATABASE_TABLE, new String[] {KEY_ROWID, KEY_TITLE,
KEY_BODY,KEY_DATE}, null, null, null, null, null);
}

/**
* Return a Cursor positioned at the note that matches the given rowId
*
* @param rowId id of note to retrieve
* @return Cursor positioned to matching note, if found
* @throws SQLException if note could not be found/retrieved
*/
public Cursor fetchNote(long rowId) throws SQLException {

Cursor mCursor =

mDb.query(true, DATABASE_TABLE, new String[] {KEY_ROWID,
KEY_TITLE, KEY_BODY,KEY_DATE}, KEY_ROWID + "=" + rowId, null,
null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;

}

/**
* Update the note using the details provided. The note to be updated is
* specified using the rowId, and it is altered to use the title and body
* values passed in
*
* @param rowId id of note to update
* @param title value to set note title to
* @param body value to set note body to
* @return true if the note was successfully updated, false otherwise
*/
public boolean updateNote(long rowId, String title, String body,String date) {
ContentValues args = new ContentValues();
args.put(KEY_TITLE, title);
args.put(KEY_BODY, body);

//This lines is added for personal reason
args.put(KEY_DATE, date);

//One more parameter is added for data
return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
}
}

Here’s the manisfest code for this project


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.note"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.note.NoteList"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<activity android:name="com.example.note
.NoteEdit"

android:label="@string/app_name"
android:windowSoftInputMode="adjustUnspecified"/>



Code above I shows is not completely all of this project. There is some files I didn’t put on here due to I want to show the main files of this project.

If you are interest with my project click here to download.

Thank you for visit my blog. Any feedback and question is welcome, please feel free to ask me question.