Friday, August 29, 2014

Setup Android adb for Wifi debug



To enable Android Debug Bridge (adb) debug via WiFi, connect IP address with the command:

$ adb connect <Android device IP>

or

$ adb connect <Android device IP>:<port>

example:
$ adb connect 192.168.1.111
(the default port number is 5555)

remark:
In my own case, i need to run the command adb tcpip (with usb connected) before connect at the first time:
adb tcpip 5555


FAQ:
- Android ADB device offline
- unable to connect to <ip address>:<port>


Check idVendor and idProduct of USB device, Arduino Uno

To check idVendor and idProduct of Arduino Uno, on Ubuntu, enter Linux command dmesg or lsusb after Uno inserted.


Sunday, August 24, 2014

Android Eclipse tips: switch between Automatic and manual target modes

In Eclipse and ADT, you can select launching your app automatically select suitable AVD/device, or manually select.

By default, a run configuration uses the automatic target mode in order to select an AVD/device. If your run configuration uses manual mode, then the "device chooser" is presented every time that your application is run, so that you can select which AVD/device to use.
http://developer.android.com/tools/building/building-eclipse.html#RunConfig

To set Run Configuration:
  • Right click your project -> Run As -> Run Configurations...
  • or, Click the arrow (downward) beside the Play button (green arrow) on the top menu -> Run Configurations...
In Run Configuration Dialog, select your project under Android Application on the left, select Target, then select your expect Deployment Target Selection Mode.



Migrating to Android for iOS Developers

Migrating to Android for iOS Developers gives you—as an experienced native iOS app developer—the skills to learn native Android apps development from scratch. Starting with preparing your Android integrated development environment and introducing just enough Android application framework fundamentals, you’ll understand how to create a simple but meaningful HelloAndroid project immediately.

Migrating to Android for iOS Developers

This book provides the guidelines and tutorial projects to show you how to translate your existing iOS app to the Android platform. You’ll use your mobile app knowledge to structure your Android apps in a similar way to how you would structure your iOS apps. To implement use cases with detailed screens, the most common mobile topics are discussed, including user interfaces, managing data, and networking with remote services. As you move through the book, you’ll create Android apps with rich UI components to handle common CRUD operations locally and remotely.

There are many Android goodies described in the book. Instead of relying on routine text descriptions, you’ll discover the uniqueness of Android and appreciate the many features that are unique to the platform. This book also explores more powerful mobile UX patterns that are commonly used on the iOS and Android platforms.

When you finish reading Migrating to Android for iOS Developers, you’ll be an Android developer as well as an iOS developer. And, you will be fully convinced you can do everything in Android that you can do in iOS.
What you’ll learn
• How to maximize your existing iOS mobile knowledge to learn Android programming skills
• How to use the Android integrated development environment with the Eclipse ADT plugin
• How to translate your existing iOS code to Android with the following common mobile topics:
° Common mobile screen navigation patterns
° User interface components and UI animations
° Storing data
° Networking and using remote services
° Using system apps
° Maps and location awareness
° Mobile search frameworks
° Mobile analytics

Who this book is for
This book is for iOS app developers—like you—who want to port their native iOS app to become an Android app. Also, if you are not an iOS developer, but already familiar with mobile apps, then this book can also help you understand Android development with step-by-step instructions and tutorial projects.

Table of Contents
1. Setup Development Environment
2. Android Programming BasicsChapter
3. Structure your App and Break it into Components
4. Implement Piece by Piece
5. More About Android Application Components
6. Android Application Resources
7. Common Mobile Use Cases
8. Pulling it all together - Recap with a Case Study
9. Appendix

Beginning Google Glass Development

Beginning Google Glass Development is your number one resource for learning how to develop for Google Glass--the paradigm-shifting mobile computing platform taking the world by storm now and for years to come. Mobile developers have always had to think for the future, and right now that means getting started with Google Glass.

Beginning Google Glass Development

This book is incredibly hands-on with many exciting projects. You will learn the basics of Glass and how to set up your development environment, through to every Glass development topic using Glass Development Kit (GDK):
• Glass User Interface
• Camera and Image Processing
• Video: Basics and Applications
• Voice and Audio
• Network, Bluetooth, and Social
• Locations, Map, and Sensors
• Graphics, Animation, and Games

You will also learn how to develop enterprise and web-based Glass apps using the Mirror API. Each topic is full of examples that illustrate what Glass can truly do and help you quickly start developing your own apps.

Jeff Tang has successfully developed mobile, web, and enterprise apps on many platforms, and cares immensely about user experience. He brings his vast knowledge to this book through cool and practical examples, which will excite and tantalize your creativity.

This book is for any developer who is keen to start developing for Glass with GDK or the Mirror API. Whether you are an Android, iOS, web, or enterprise developer, you do not want to miss the chance that Glass becomes the next big thing. Get started with Beginning Google Glass Development and be inspired today.

What you’ll learn
• Glass User Interface
• Camera and Image Processing
• Video: Basics and Applications
• Voice and Audio
• Network, Bluetooth, and Social
• Locations, Map, and Sensors
• Graphics, Animation, and Games

Who this book is for
This book is for any developer who is keen to start developing for Glass. You may have worked with iOS apps, Android apps, or both – but you can start developing with Glass today using this book.

Table of Contents
01 - Getting Started
02 - Hello Glass! Your First GDK Glassware
03 - Glass User Interface
04 - Camera and Image Processing
05 - Video: Basics and Applications
06 - Voice and Audio
07 - Networking, Bluetooth, and Social
08 - Locations, Maps, and Sensors
09 - Graphics, Animations, and Games
10 - The Mirror API (The Mirror API and Enterprise Apps)

Thursday, August 21, 2014

PhoneGap 3.x Mobile Application Development Hotshot

Create useful and exciting real-world apps for iOS and Android devices with 12 fantastic projects with this book and ebook.

PhoneGap 3.x Mobile Application Development Hotshot

Overview
  • Use PhoneGap 3.x effectively to build real, functional mobile apps ranging from productivity apps to a simple arcade game
  • Explore often-used design patterns in apps designed for mobile devices
  • Fully practical, project-based approach to give you the confidence in developing your app independently
In Detail

PhoneGap allows you to use your existing knowledge of HTML, CSS, and JavaScript to create useful and exciting mobile applications.

This book will present you with 12 exciting projects that will introduce you to the dynamic world of app development in PhoneGap. Starting with their design and following through to their completion, you will develop real-world mobile applications. Each app uses a combination of core PhoneGap technologies, plugins, and various frameworks covering the necessary concepts you can use to create many more great apps for mobile devices.

What you will learn from this book
  • Explore localization and globalization
  • Create, save, and retrieve data using persistent device storage
  • Record audio using a microphone
  • Capture images and video using a camera
  • Share content to social media networks
  • Optimize your app for tablet-sized devices
  • Locate the user's device using geolocation
  • Interact with the accelerometer to create a fun arcade game
  • Use core and third-party plugins to extend PhoneGap
  • Look at mobile application design patterns
Approach

A practical guide written in a tutorial-style, this book walks you step-by-step through 12 individual projects to create real world apps. Each project moves through design and implementation of the app, and also provides suggestions to enhance it.

Who this book is written for

If you are a mobile developer who is familiar with Phonegap basics and wants to quickly create some cool mobile applications with Phonegap, this book is for you. You should have some experience working with JavaScript, HTML, CSS, and also be able to use your operating system's command-line interface. No experience with Java, C#, or Objective C is required.



Tuesday, August 19, 2014

Java Chat Server running on PC command line

The former post show how to "Implement simple Android Chat Application, server side" running on Android. Actually, it show info of IP/Port only, without any user interaction. This post is another command line version of the Chat Server in Java, it can run on PC's ommand Line. It can connected with "Simple Android Chat Application, client side".

The video show it was compiled with SDK 8, and run on command line, at PC running Ubuntu Linux.


JavaCmdChatServer.java
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class JavaCmdChatServer {

    static final int SocketServerPORT = 8080;

    String msgLog = "";

    List<ChatClient> userList;

    ServerSocket serverSocket;

    public static void main(String[] args) {
        JavaCmdChatServer ChatServer = new JavaCmdChatServer();

        while (true) {
        }
    }

    JavaCmdChatServer() {
        System.out.print(getIpAddress());
        userList = new ArrayList<>();
        ChatServerThread chatServerThread = new ChatServerThread();
        chatServerThread.start();

    }

    private class ChatServerThread extends Thread {

        @Override
        public void run() {
            Socket socket = null;

            try {
                serverSocket = new ServerSocket(SocketServerPORT);
                System.out.println("I'm waiting here: "
                    + serverSocket.getLocalPort());
                    System.out.println("CTRL + C to quit");

                while (true) {
                    socket = serverSocket.accept();
                    ChatClient client = new ChatClient();
                    userList.add(client);
                    ConnectThread connectThread = new ConnectThread(client, socket);
                    connectThread.start();
                }

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }

        }

    }

    private class ConnectThread extends Thread {

        Socket socket;
        ChatClient connectClient;
        String msgToSend = "";

        ConnectThread(ChatClient client, Socket socket) {
            connectClient = client;
            this.socket = socket;
            client.socket = socket;
            client.chatThread = this;
        }

        @Override
        public void run() {
            DataInputStream dataInputStream = null;
            DataOutputStream dataOutputStream = null;

            try {
                dataInputStream = new DataInputStream(socket.getInputStream());
                dataOutputStream = new DataOutputStream(socket.getOutputStream());

                String n = dataInputStream.readUTF();

                connectClient.name = n;

                msgLog = connectClient.name + " connected@"
                    + connectClient.socket.getInetAddress()
                    + ":" + connectClient.socket.getPort() + "\n";

                System.out.println(msgLog);

                dataOutputStream.writeUTF("Welcome " + n + "\n");
                dataOutputStream.flush();

                broadcastMsg(n + " join our chat.\n");

                while (true) {
                    if (dataInputStream.available() > 0) {
                        String newMsg = dataInputStream.readUTF();

                        msgLog = n + ": " + newMsg;
                        System.out.print(msgLog);
                        broadcastMsg(n + ": " + newMsg);
                    }

                    if (!msgToSend.equals("")) {
                        dataOutputStream.writeUTF(msgToSend);
                        dataOutputStream.flush();
                        msgToSend = "";
                    }

                }

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (dataInputStream != null) {
                    try {
                        dataInputStream.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                if (dataOutputStream != null) {
                    try {
                        dataOutputStream.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

                userList.remove(connectClient);

                System.out.println(connectClient.name + " removed.");

                msgLog = "-- " + connectClient.name + " leaved\n";
                System.out.println(msgLog);

                broadcastMsg("-- " + connectClient.name + " leaved\n");

            }

        }

        private void sendMsg(String msg) {
            msgToSend = msg;
        }

    }

    private void broadcastMsg(String msg) {
        for (int i = 0; i < userList.size(); i++) {
            userList.get(i).chatThread.sendMsg(msg);
            msgLog = "- send to " + userList.get(i).name + "\n";
            System.out.print(msgLog);
        }
        System.out.println();
        
    }

    private String getIpAddress() {
        String ip = "";
        try {
            Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
                .getNetworkInterfaces();
            while (enumNetworkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = enumNetworkInterfaces
                    .nextElement();
                Enumeration<InetAddress> enumInetAddress = networkInterface
                    .getInetAddresses();
                while (enumInetAddress.hasMoreElements()) {
                    InetAddress inetAddress = enumInetAddress.nextElement();

                    if (inetAddress.isSiteLocalAddress()) {
                        ip += "SiteLocalAddress: "
                            + inetAddress.getHostAddress() + "\n";
                    }

                }

            }

        } catch (SocketException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            ip += "Something Wrong! " + e.toString() + "\n";
        }

        return ip;
    }

    class ChatClient {

        String name;
        Socket socket;
        ConnectThread chatThread;

    }

}

download filesDownload the files.

Monday, August 18, 2014

Simple Android Chat Application, client side.

It's client side of Simple Android Chat Application, for the server side, refer last post "Implement simple Android Chat Application, server side".


MainActivity.java
package com.example.androidchatclient;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {
 
 static final int SocketServerPORT = 8080;
 
 LinearLayout loginPanel, chatPanel;

 EditText editTextUserName, editTextAddress;
 Button buttonConnect;
 TextView chatMsg, textPort;
 
 EditText editTextSay;
 Button buttonSend;
 Button buttonDisconnect;

 String msgLog = "";
 
 ChatClientThread chatClientThread = null;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  loginPanel = (LinearLayout)findViewById(R.id.loginpanel);
  chatPanel = (LinearLayout)findViewById(R.id.chatpanel);

  editTextUserName = (EditText) findViewById(R.id.username);
  editTextAddress = (EditText) findViewById(R.id.address);
  textPort = (TextView) findViewById(R.id.port);
  textPort.setText("port: " + SocketServerPORT);
  buttonConnect = (Button) findViewById(R.id.connect);
  buttonDisconnect = (Button) findViewById(R.id.disconnect);
  chatMsg = (TextView) findViewById(R.id.chatmsg);

  buttonConnect.setOnClickListener(buttonConnectOnClickListener);
  buttonDisconnect.setOnClickListener(buttonDisconnectOnClickListener);
  
  editTextSay = (EditText)findViewById(R.id.say);
  buttonSend = (Button)findViewById(R.id.send);
  
  buttonSend.setOnClickListener(buttonSendOnClickListener);
 }
 
 OnClickListener buttonDisconnectOnClickListener = new OnClickListener() {

  @Override
  public void onClick(View v) {
   if(chatClientThread==null){
    return;
   }
   chatClientThread.disconnect();
  }
  
 };
 
 OnClickListener buttonSendOnClickListener = new OnClickListener() {

  @Override
  public void onClick(View v) {
   if (editTextSay.getText().toString().equals("")) {
    return;
   }
   
   if(chatClientThread==null){
    return;
   }
   
   chatClientThread.sendMsg(editTextSay.getText().toString() + "\n");
  }
  
 };

 OnClickListener buttonConnectOnClickListener = new OnClickListener() {

  @Override
  public void onClick(View v) {
   String textUserName = editTextUserName.getText().toString();
   if (textUserName.equals("")) {
    Toast.makeText(MainActivity.this, "Enter User Name",
      Toast.LENGTH_LONG).show();
    return;
   }

   String textAddress = editTextAddress.getText().toString();
   if (textAddress.equals("")) {
    Toast.makeText(MainActivity.this, "Enter Addresse",
      Toast.LENGTH_LONG).show();
    return;
   }
   
   msgLog = "";
   chatMsg.setText(msgLog);
   loginPanel.setVisibility(View.GONE);
   chatPanel.setVisibility(View.VISIBLE);

   chatClientThread = new ChatClientThread(
     textUserName, textAddress, SocketServerPORT);
   chatClientThread.start();
  }

 };

 private class ChatClientThread extends Thread {

  String name;
  String dstAddress;
  int dstPort;
  
  String msgToSend = "";
  boolean goOut = false;

  ChatClientThread(String name, String address, int port) {
   this.name = name;
   dstAddress = address;
   dstPort = port;
  }

  @Override
  public void run() {
   Socket socket = null;
   DataOutputStream dataOutputStream = null;
   DataInputStream dataInputStream = null;

   try {
    socket = new Socket(dstAddress, dstPort);
    dataOutputStream = new DataOutputStream(
      socket.getOutputStream());
    dataInputStream = new DataInputStream(socket.getInputStream());
    dataOutputStream.writeUTF(name);
    dataOutputStream.flush();

    while (!goOut) {
     if (dataInputStream.available() > 0) {
      msgLog += dataInputStream.readUTF();

      MainActivity.this.runOnUiThread(new Runnable() {

       @Override
       public void run() {
        chatMsg.setText(msgLog);
       }
      });
     }
     
     if(!msgToSend.equals("")){
      dataOutputStream.writeUTF(msgToSend);
      dataOutputStream.flush();
      msgToSend = "";
     }
    }

   } catch (UnknownHostException e) {
    e.printStackTrace();
    final String eString = e.toString();
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, eString, Toast.LENGTH_LONG).show();
     }
     
    });
   } catch (IOException e) {
    e.printStackTrace();
    final String eString = e.toString();
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, eString, Toast.LENGTH_LONG).show();
     }
     
    });
   } finally {
    if (socket != null) {
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    if (dataOutputStream != null) {
     try {
      dataOutputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    if (dataInputStream != null) {
     try {
      dataInputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      loginPanel.setVisibility(View.VISIBLE);
      chatPanel.setVisibility(View.GONE);
     }
     
    });
   }

  }
  
  private void sendMsg(String msg){
   msgToSend = msg;
  }
  
  private void disconnect(){
   goOut = true;
  }
 }

}

/res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Char Client"
        android:textStyle="bold" />

    <LinearLayout
        android:id="@+id/loginpanel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:visibility="visible" >

        <EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="User name" />

        <EditText
            android:id="@+id/address"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="dstAddress" />

        <TextView
            android:id="@+id/port"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/connect"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Connect..." />
    </LinearLayout>

 <LinearLayout
        android:id="@+id/chatpanel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:visibility="gone" >
        
        <EditText
            android:id="@+id/say"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Say something" />
     
        <Button
            android:id="@+id/send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Send" />
        
        <Button
            android:id="@+id/disconnect"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Disconnect" />

        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <TextView
                android:id="@+id/chatmsg"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </ScrollView>
    </LinearLayout>

</LinearLayout>

Permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.

download filesDownload the files.

Implement simple Android Chat Application, server side.

It's a simple example of Chat app running on Android devices, both server and clients. One device run AndroidChatServer to wait connection from clients, other devices run AndroidChatClient to connect to the server. Any AndroidChatClient can send message to server, then server broadcast to all clients.


Here is the code in Server side, Client side can be found in next post, "Simple Android Chat Application, client side"
.
MainActivity.java
package com.example.androidchatserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import android.support.v7.app.ActionBarActivity;
import android.widget.TextView;
import android.widget.Toast;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {

 static final int SocketServerPORT = 8080;

 TextView infoIp, infoPort, chatMsg;

 String msgLog = "";
 
 List<ChatClient> userList;

 ServerSocket serverSocket;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  infoIp = (TextView) findViewById(R.id.infoip);
  infoPort = (TextView) findViewById(R.id.infoport);
  chatMsg = (TextView) findViewById(R.id.chatmsg);

  infoIp.setText(getIpAddress());

  userList = new ArrayList<ChatClient>();
  
  ChatServerThread chatServerThread = new ChatServerThread();
  chatServerThread.start();
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();

  if (serverSocket != null) {
   try {
    serverSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }

 private class ChatServerThread extends Thread {

  @Override
  public void run() {
   Socket socket = null;

   try {
    serverSocket = new ServerSocket(SocketServerPORT);
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      infoPort.setText("I'm waiting here: "
        + serverSocket.getLocalPort());
     }
    });
    
    while (true) {
     socket = serverSocket.accept();
     ChatClient client = new ChatClient();
     userList.add(client);
     ConnectThread connectThread = new ConnectThread(client, socket);
     connectThread.start();
    }

   } catch (IOException e) {
    e.printStackTrace();
   } finally {
    if (socket != null) {
     try {
      socket.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
   }

  }

 }
 
 private class ConnectThread extends Thread {
  
  Socket socket;
  ChatClient connectClient;
  String msgToSend = "";

  ConnectThread(ChatClient client, Socket socket){
   connectClient = client;
   this.socket= socket;
   client.socket = socket;
   client.chatThread = this;
  }

  @Override
  public void run() {
   DataInputStream dataInputStream = null;
   DataOutputStream dataOutputStream = null;
   
   try {
    dataInputStream = new DataInputStream(socket.getInputStream());
    dataOutputStream = new DataOutputStream(socket.getOutputStream());
    
    String n = dataInputStream.readUTF();
    
    connectClient.name = n;
    
    msgLog += connectClient.name + " connected@" + 
      connectClient.socket.getInetAddress() + 
      ":" + connectClient.socket.getPort() + "\n";
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      chatMsg.setText(msgLog);
     }
    });
    
    dataOutputStream.writeUTF("Welcome " + n + "\n");
    dataOutputStream.flush();
    
    broadcastMsg(n + " join our chat.\n");
    
    while (true) {
     if (dataInputStream.available() > 0) {
      String newMsg = dataInputStream.readUTF();
      
      
      msgLog += n + ": " + newMsg;
      MainActivity.this.runOnUiThread(new Runnable() {

       @Override
       public void run() {
        chatMsg.setText(msgLog);
       }
      });
      
      broadcastMsg(n + ": " + newMsg);
     }
     
     if(!msgToSend.equals("")){
      dataOutputStream.writeUTF(msgToSend);
      dataOutputStream.flush();
      msgToSend = "";
     }
     
    }
    
   } catch (IOException e) {
    e.printStackTrace();
   } finally {
    if (dataInputStream != null) {
     try {
      dataInputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }

    if (dataOutputStream != null) {
     try {
      dataOutputStream.close();
     } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
    
    userList.remove(connectClient);
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      Toast.makeText(MainActivity.this, 
       connectClient.name + " removed.", Toast.LENGTH_LONG).show();
      
      msgLog += "-- " + connectClient.name + " leaved\n";
      MainActivity.this.runOnUiThread(new Runnable() {

       @Override
       public void run() {
        chatMsg.setText(msgLog);
       }
      });
      
      broadcastMsg("-- " + connectClient.name + " leaved\n");
     }
    });
   }
   
  }
  
  private void sendMsg(String msg){
   msgToSend = msg;
  }
  
 }
 
 private void broadcastMsg(String msg){
  for(int i=0; i<userList.size(); i++){
   userList.get(i).chatThread.sendMsg(msg);
   msgLog += "- send to " + userList.get(i).name + "\n";
  }
  
  MainActivity.this.runOnUiThread(new Runnable() {

   @Override
   public void run() {
    chatMsg.setText(msgLog);
   }
  });
 }

 private String getIpAddress() {
  String ip = "";
  try {
   Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
     .getNetworkInterfaces();
   while (enumNetworkInterfaces.hasMoreElements()) {
    NetworkInterface networkInterface = enumNetworkInterfaces
      .nextElement();
    Enumeration<InetAddress> enumInetAddress = networkInterface
      .getInetAddresses();
    while (enumInetAddress.hasMoreElements()) {
     InetAddress inetAddress = enumInetAddress.nextElement();

     if (inetAddress.isSiteLocalAddress()) {
      ip += "SiteLocalAddress: "
        + inetAddress.getHostAddress() + "\n";
     }

    }

   }

  } catch (SocketException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   ip += "Something Wrong! " + e.toString() + "\n";
  }

  return ip;
 }

 class ChatClient {
  String name;
  Socket socket;
  ConnectThread chatThread;
  
 }

}

/res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Char Server"
        android:textStyle="bold" />
    
    <TextView
        android:id="@+id/infoport"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="italic" />

    <TextView
        android:id="@+id/infoip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textStyle="italic" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <TextView
            android:id="@+id/chatmsg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </ScrollView>

</LinearLayout>

make sure Add uses-permission of "android.permission.INTERNET" to AndroidManifest.xml.

download filesDownload the files.

Related:
- Command line version Chat Server.

Next:
Android Chat example, with server sending individual message to specify client.


Added@2014-12-06

If you found "Something Wrong! java.net.SocketException" displayed.

Make sure add permission of "android.permission.INTERNET" in AndroidManifest.xml. It's a common error of missing "android.permission.INTERNET" to cause SocketException.


Saturday, August 16, 2014

Implement simple HTTP server running on Android

Example to implement simple HTTP server on Android:


MainActivity.java
package com.example.androidhttpserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;

import android.support.v7.app.ActionBarActivity;
import android.widget.EditText;
import android.widget.TextView;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {

 EditText welcomeMsg;
 TextView infoIp;
 TextView infoMsg;
 String msgLog = "";
 
 ServerSocket httpServerSocket;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  welcomeMsg = (EditText) findViewById(R.id.welcomemsg);
  infoIp = (TextView) findViewById(R.id.infoip);
  infoMsg = (TextView) findViewById(R.id.msg);

  infoIp.setText(getIpAddress() + ":" 
   + HttpServerThread.HttpServerPORT + "\n");

  HttpServerThread httpServerThread = new HttpServerThread();
  httpServerThread.start();
 }
 
 @Override
 protected void onDestroy() {
  super.onDestroy();

  if (httpServerSocket != null) {
   try {
    httpServerSocket.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

 private String getIpAddress() {
  String ip = "";
  try {
   Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
     .getNetworkInterfaces();
   while (enumNetworkInterfaces.hasMoreElements()) {
    NetworkInterface networkInterface = enumNetworkInterfaces
      .nextElement();
    Enumeration<InetAddress> enumInetAddress = networkInterface
      .getInetAddresses();
    while (enumInetAddress.hasMoreElements()) {
     InetAddress inetAddress = enumInetAddress.nextElement();

     if (inetAddress.isSiteLocalAddress()) {
      ip += "SiteLocalAddress: "
        + inetAddress.getHostAddress() + "\n";
     }

    }

   }

  } catch (SocketException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   ip += "Something Wrong! " + e.toString() + "\n";
  }

  return ip;
 }
 
 private class HttpServerThread extends Thread {
  
  static final int HttpServerPORT = 8888;

  @Override
  public void run() {
   Socket socket = null;
   
   try {
    httpServerSocket = new ServerSocket(HttpServerPORT);
    
    while(true){
     socket = httpServerSocket.accept();

     HttpResponseThread httpResponseThread = 
      new HttpResponseThread(
       socket, 
       welcomeMsg.getText().toString());
     httpResponseThread.start();
    }
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }

  }

  
 }
 
 private class HttpResponseThread extends Thread {
  
  Socket socket;
  String h1;
  
  HttpResponseThread(Socket socket, String msg){
   this.socket = socket;
   h1 = msg;
  }

  @Override
  public void run() {
   BufferedReader is;
   PrintWriter os;
   String request;
   
   
   try {
    is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    request = is.readLine();
    
    os = new PrintWriter(socket.getOutputStream(), true);
    
    String response = 
     "<html><head></head>" +
     "<body>" +
     "<h1>" + h1 + "</h1>" +
     "</body></html>";
    
    os.print("HTTP/1.0 200" + "\r\n");
    os.print("Content type: text/html" + "\r\n");
    os.print("Content length: " + response.length() + "\r\n");
    os.print("\r\n");
    os.print(response + "\r\n");
    os.flush();
    socket.close();
    
    
    msgLog += "Request of " + request 
      + " from " + socket.getInetAddress().toString() + "\n";
    MainActivity.this.runOnUiThread(new Runnable() {

     @Override
     public void run() {
      
      infoMsg.setText(msgLog);
     }
    });
    
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
   return;
  }
 }

}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <EditText
        android:id="@+id/welcomemsg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Welcome from Android-er" />

    <TextView
        android:id="@+id/infoip"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <TextView
            android:id="@+id/msg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </ScrollView>

</LinearLayout>

download filesDownload the files.

Related:
Simple web server using org.apache.http.protocol.HttpService

Updated@2015-11-25:
Permission of "android.permission.INTERNET" is needed in AndroidManifest.xml.

Updated@2015-11-26:
This code NOT work on Android 5, may be all 5+ version.
Fixed, refer post "socket.getInetAddress() return null on Android 5".

Friday, August 15, 2014

Install VirtualBox 4.3 on Ubuntu 14.04 from repository source

This post show how to install VirtualBox 4.3 on Ubuntu 14.04, from repository.




The list of repository sources can be found at https://www.virtualbox.org/wiki/Linux_Downloads. For 14.04 ("Trusty Tahr"), it is "deb http://download.virtualbox.org/virtualbox/debian trusty contrib".



Run the command to add apt repository to your sources list:
$ sudo add-apt-repository "deb http://download.virtualbox.org/virtualbox/debian trusty contrib"

Before update apt source list, you have to add Oracle public key. Download the Oracle public key for apt-secure (oracle_vbox.asc) from the same page. It should be like this.

Then run the command:
sudo apt-key add oracle_vbox.asc

Update apt-get and install VirtualBox 4.3:
$ sudo apt-get update
$ sudo apt-get install virtualbox-4.3


Thursday, August 14, 2014

Capture image generated by Google Charts API

Previous posts show how to "Display Google Charts (pie chart) on Android WebView" and "More Google Charts examples on Android WebView". To capture the PNG image of a chart, we can use the getImageURI() method, it return a string in "data:image/png;base64,..." format.


We can pass this string to Android code, decode and generate bitmap. To decode string in "data:image/png;base64,..." format, to Bitmap, we can use the code:
 private Bitmap decodeBase64PNG(String src){

  String imageDataBytes = src.substring(src.indexOf(",") + 1);
  
  InputStream stream = 
   new ByteArrayInputStream(
    Base64.decode(imageDataBytes.getBytes(), 
    Base64.DEFAULT));
  
     Bitmap bitmap = BitmapFactory.decodeStream(stream);
     return bitmap;
 }

For MainActivity.java, activity_main.xml and AndroidManifest.xml, refer to last post "Display Google Charts (pie chart) on Android WebView".

Other files modify from last post "More Google Charts examples on Android WebView".

Modify layout_webchart.xml to add a Button to Capture the image.
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <Spinner
        android:id="@+id/spcharts"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <Button
        android:id="@+id/capture"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Capture" />
    
    <WebView
        android:id="@+id/web"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

ShowWebChartActivity.java
package com.example.androidwebchart;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Base64;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.Toast;

@SuppressLint("SetJavaScriptEnabled") 
public class ShowWebChartActivity extends ActionBarActivity {
 
 WebView webView;
 int num1, num2, num3, num4, num5;
 
 Spinner spCharts;
 List<String> listCharts;
 List<String> listHtml;
 
 Button btnCapture;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_webchart);
        
        Intent intent = getIntent();
        num1 = intent.getIntExtra("NUM1", 0);
        num2 = intent.getIntExtra("NUM2", 0);
        num3 = intent.getIntExtra("NUM3", 0);
        num4 = intent.getIntExtra("NUM4", 0);
        num5 = intent.getIntExtra("NUM5", 0);
        
        spCharts = (Spinner) findViewById(R.id.spcharts);
        
        listCharts = new ArrayList<String>();
        listCharts.add("Pie Chart");
        listCharts.add("Pie Chart 3D");
        listCharts.add("Scatter Chart");
        listCharts.add("Column Chart");
        listCharts.add("Bar Chart");
        listCharts.add("Histogram");
        listCharts.add("Line Chart");
        listCharts.add("Area Chart");
        
        listHtml = new ArrayList<String>();
        listHtml.add("file:///android_asset/pie_chart.html");
        listHtml.add("file:///android_asset/pie_chart_3d.html");
        listHtml.add("file:///android_asset/scatter_chart.html");
        listHtml.add("file:///android_asset/column_chart.html");
        listHtml.add("file:///android_asset/bar_chart.html");
        listHtml.add("file:///android_asset/histogram.html");
        listHtml.add("file:///android_asset/line_chart.html");
        listHtml.add("file:///android_asset/area_chart.html");
        
     ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
      android.R.layout.simple_spinner_item, listCharts);
     dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
     spCharts.setAdapter(dataAdapter);
     spCharts.setOnItemSelectedListener(new OnItemSelectedListener(){

   @Override
   public void onItemSelected(AdapterView<?> parent, View view,
     int position, long id) {
    String chartHtml = listHtml.get(parent.getSelectedItemPosition());
    webView.loadUrl(chartHtml);
   }

   @Override
   public void onNothingSelected(AdapterView<?> parent) {
    // TODO Auto-generated method stub
    
   }});
        
        webView = (WebView)findViewById(R.id.web);
        webView.addJavascriptInterface(new WebAppInterface(), "Android");

        webView.getSettings().setJavaScriptEnabled(true); 

        btnCapture = (Button)findViewById(R.id.capture);
        btnCapture.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    //call Javascript in WebView/HTML
    webView.loadUrl("javascript:capture()");
   }});
 }
 
 private void showCaptured(String imageuri){

  Bitmap bmp = decodeBase64PNG(imageuri);
  
  Dialog dialog = new Dialog(this);
     ImageView imageView = new ImageView(this);
     imageView.setImageBitmap(bmp);
     dialog.addContentView(
       imageView, 
       new LayoutParams(
        LayoutParams.MATCH_PARENT, 
        LayoutParams.MATCH_PARENT));
     dialog.show();
  
 }
 
 private Bitmap decodeBase64PNG(String src){

  String imageDataBytes = src.substring(src.indexOf(",") + 1);
  
  InputStream stream = 
   new ByteArrayInputStream(
    Base64.decode(imageDataBytes.getBytes(), 
    Base64.DEFAULT));
  
     Bitmap bitmap = BitmapFactory.decodeStream(stream);
     return bitmap;
 }

 public class WebAppInterface {

     @JavascriptInterface
  public int getNum1() {
   return num1;
  }
  
  @JavascriptInterface
  public int getNum2() {
   return num2;
  }
  
  @JavascriptInterface
  public int getNum3() {
   return num3;
  }
  
  @JavascriptInterface
  public int getNum4() {
   return num4;
  }
  
  @JavascriptInterface
  public int getNum5() {
   return num5;
  }
  
  @JavascriptInterface
  public void captureCallback(String imageURI){
   Toast.makeText(ShowWebChartActivity.this, 
    imageURI, Toast.LENGTH_LONG).show();
   showCaptured(imageURI);
  }
 }

}

All other HTMLs:

  • add a method Javascript function capture() to be called from Android, and call chart.getImageURI() to get image, and pass back to Android by calling captureCallback().
  • Make chart to global by removing "var" in front of it.

pie_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/quick_start-->
<html>
  <head>
    <!--Load the AJAX API-->
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
    
      // Load the Visualization API and the piechart package.
      google.load('visualization', '1.0', {'packages':['corechart']});
      
      // Set a callback to run when the Google Visualization API is loaded.
      google.setOnLoadCallback(drawChart);


      // Callback that creates and populates a data table, 
      // instantiates the pie chart, passes in the data and
      // draws it.
      function drawChart() {

      // Create the data table.
      var data = new google.visualization.DataTable();
      data.addColumn('string', 'ITEM');
      data.addColumn('number', 'VALUE');
      data.addRows([
        ['Item 1', Android.getNum1()],
        ['Item 2', Android.getNum2()],
        ['Item 3', Android.getNum3()], 
        ['Item 4', Android.getNum4()],
        ['Item 5', Android.getNum5()]
      ]);

      // Set chart options
      var options = {'title':'Android-er: Google Charts example of Pie chart'};

      // Instantiate and draw our chart, passing in some options.
      chart = new google.visualization.PieChart(document.getElementById('chart_div'));
      chart.draw(data, options);
    }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>

  <body>
 <!--Div that will hold the pie chart-->
    <div id="chart_div" style="width:100%; height:100%"></div>
  </body>
</html>

pie_chart_3d.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/piechart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items',  'Value'],
          ['Item 1', Android.getNum1()],
          ['Item 2', Android.getNum2()],
          ['Item 3', Android.getNum3()],
          ['Item 4', Android.getNum4()],
          ['Item 5', Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of 3D Pie chart',
          is3D: true,
        };

        chart = new google.visualization.PieChart(document.getElementById('piechart_3d'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="piechart_3d" style="width: 100%; height: 100%;"></div>
  </body>
</html>

scatter_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/scatterchart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['x', 'Value'],
          [ 1, Android.getNum1()],
          [ 2, Android.getNum2()],
          [ 3, Android.getNum3()],
          [ 4, Android.getNum4()],
          [ 5, Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Scatter chart',
          hAxis: {title: 'X'},
          vAxis: {title: 'Value'},
          legend: 'none'
        };

        chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

column_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/columnchart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {

  var data = google.visualization.arrayToDataTable([
    ['Items', 'Value'],
    ['Item 1',  Android.getNum1()],
    ['Item 2',  Android.getNum2()],
    ['Item 3',  Android.getNum3()],
    ['Item 4',  Android.getNum4()],
    ['Item 5',  Android.getNum5()]
  ]);

  var options = {
    title: 'Android-er: Google Charts example of Column chart',
    hAxis: {title: 'Value', titleTextStyle: {color: 'red'}}
  };

  chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));

  chart.draw(data, options);

}
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

bar_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/barchart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1',  Android.getNum1()],
          ['Item 2',  Android.getNum2()],
          ['Item 3',  Android.getNum3()],
          ['Item 4',  Android.getNum4()],
          ['Item 5',  Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Bar chart',
          vAxis: {title: 'Value',  titleTextStyle: {color: 'red'}}
        };

        chart = new google.visualization.BarChart(document.getElementById('chart_div'));

        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

histogram.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/histogram-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1', Android.getNum1()],
          ['Item 2', Android.getNum2()],
          ['Item 3', Android.getNum3()],
          ['Item 4', Android.getNum4()],
          ['Item 5', Android.getNum5()]]);

        var options = {
          title: 'Android-er: Google Charts example of Histogram',
          legend: { position: 'none' },
        };

        chart = new google.visualization.Histogram(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

line_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/linechart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1',  Android.getNum1()],
          ['Item 2',  Android.getNum2()],
          ['Item 3',  Android.getNum3()],
          ['Item 4',  Android.getNum4()],
          ['Item 5',  Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Line chart'
        };

        chart = new google.visualization.LineChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

area_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/areachart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1',  Android.getNum1()],
          ['Item 2',  Android.getNum2()],
          ['Item 3',  Android.getNum3()],
          ['Item 4',  Android.getNum4()],
          ['Item 5',  Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Area chart',
          hAxis: {title: 'Value',  titleTextStyle: {color: '#333'}},
          vAxis: {minValue: 0}
        };

        chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
    
    <script type="text/javascript">
    function capture(){
     Android.captureCallback(chart.getImageURI());
    }
    </script>
    
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

download filesDownload the files.

More Google Charts examples on Android WebView

Last post show simple example of using Google Charts API in WebView. Now I show more chart examples, include: Pie Chart, 3D Pie Chart, Scatter Chart, Column Chart, Bar Chart, Histogram, Line Chart and Area Chart.



For MainActivity.java, activity_main.xml and AndroidManifest.xml, refer to last post "Display Google Charts (pie chart) on Android WebView".

Modify ShowWebChartActivity.java to provide a Spinner for user to select various type of charts, and load coresponding html accordingly.

package com.example.androidwebchart;

import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;

@SuppressLint("SetJavaScriptEnabled") 
public class ShowWebChartActivity extends ActionBarActivity {
 
 WebView webView;
 int num1, num2, num3, num4, num5;
 
 Spinner spCharts;
 List<String> listCharts;
 List<String> listHtml;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_webchart);
        
        Intent intent = getIntent();
        num1 = intent.getIntExtra("NUM1", 0);
        num2 = intent.getIntExtra("NUM2", 0);
        num3 = intent.getIntExtra("NUM3", 0);
        num4 = intent.getIntExtra("NUM4", 0);
        num5 = intent.getIntExtra("NUM5", 0);
        
        spCharts = (Spinner) findViewById(R.id.spcharts);
        
        listCharts = new ArrayList<String>();
        listCharts.add("Pie Chart");
        listCharts.add("Pie Chart 3D");
        listCharts.add("Scatter Chart");
        listCharts.add("Column Chart");
        listCharts.add("Bar Chart");
        listCharts.add("Histogram");
        listCharts.add("Line Chart");
        listCharts.add("Area Chart");
        
        listHtml = new ArrayList<String>();
        listHtml.add("file:///android_asset/pie_chart.html");
        listHtml.add("file:///android_asset/pie_chart_3d.html");
        listHtml.add("file:///android_asset/scatter_chart.html");
        listHtml.add("file:///android_asset/column_chart.html");
        listHtml.add("file:///android_asset/bar_chart.html");
        listHtml.add("file:///android_asset/histogram.html");
        listHtml.add("file:///android_asset/line_chart.html");
        listHtml.add("file:///android_asset/area_chart.html");
        
     ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
      android.R.layout.simple_spinner_item, listCharts);
     dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
     spCharts.setAdapter(dataAdapter);
     spCharts.setOnItemSelectedListener(new OnItemSelectedListener(){

   @Override
   public void onItemSelected(AdapterView<?> parent, View view,
     int position, long id) {
    String chartHtml = listHtml.get(parent.getSelectedItemPosition());
    webView.loadUrl(chartHtml);
   }

   @Override
   public void onNothingSelected(AdapterView<?> parent) {
    // TODO Auto-generated method stub
    
   }});
        
        webView = (WebView)findViewById(R.id.web);
        webView.addJavascriptInterface(new WebAppInterface(), "Android");

        webView.getSettings().setJavaScriptEnabled(true); 

 }

 public class WebAppInterface {

     @JavascriptInterface
  public int getNum1() {
   return num1;
  }
  
  @JavascriptInterface
  public int getNum2() {
   return num2;
  }
  
  @JavascriptInterface
  public int getNum3() {
   return num3;
  }
  
  @JavascriptInterface
  public int getNum4() {
   return num4;
  }
  
  @JavascriptInterface
  public int getNum5() {
   return num5;
  }
 }

}

layout_webchart.xml
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <Spinner
        android:id="@+id/spcharts"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    
    <WebView
        android:id="@+id/web"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

Create various html for various type.

/assets/pie_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/quick_start-->
<html>
  <head>
    <!--Load the AJAX API-->
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
    
      // Load the Visualization API and the piechart package.
      google.load('visualization', '1.0', {'packages':['corechart']});
      
      // Set a callback to run when the Google Visualization API is loaded.
      google.setOnLoadCallback(drawChart);


      // Callback that creates and populates a data table, 
      // instantiates the pie chart, passes in the data and
      // draws it.
      function drawChart() {

      // Create the data table.
      var data = new google.visualization.DataTable();
      data.addColumn('string', 'ITEM');
      data.addColumn('number', 'VALUE');
      data.addRows([
        ['Item 1', Android.getNum1()],
        ['Item 2', Android.getNum2()],
        ['Item 3', Android.getNum3()], 
        ['Item 4', Android.getNum4()],
        ['Item 5', Android.getNum5()]
      ]);

      // Set chart options
      var options = {'title':'Android-er: Google Charts example of Pie chart'};

      // Instantiate and draw our chart, passing in some options.
      var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
      chart.draw(data, options);
    }
    </script>
  </head>

  <body>
 <!--Div that will hold the pie chart-->
    <div id="chart_div" style="width:100%; height:100%"></div>
  </body>
</html>

/assets/pie_chart_3d.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/piechart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items',  'Value'],
          ['Item 1', Android.getNum1()],
          ['Item 2', Android.getNum2()],
          ['Item 3', Android.getNum3()],
          ['Item 4', Android.getNum4()],
          ['Item 5', Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of 3D Pie chart',
          is3D: true,
        };

        var chart = new google.visualization.PieChart(document.getElementById('piechart_3d'));
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
    <div id="piechart_3d" style="width: 100%; height: 100%;"></div>
  </body>
</html>

/assets/scatter_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/scatterchart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['x', 'Value'],
          [ 1, Android.getNum1()],
          [ 2, Android.getNum2()],
          [ 3, Android.getNum3()],
          [ 4, Android.getNum4()],
          [ 5, Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Scatter chart',
          hAxis: {title: 'X'},
          vAxis: {title: 'Value'},
          legend: 'none'
        };

        var chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

/assets/column_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/columnchart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {

  var data = google.visualization.arrayToDataTable([
    ['Items', 'Value'],
    ['Item 1',  Android.getNum1()],
    ['Item 2',  Android.getNum2()],
    ['Item 3',  Android.getNum3()],
    ['Item 4',  Android.getNum4()],
    ['Item 5',  Android.getNum5()]
  ]);

  var options = {
    title: 'Android-er: Google Charts example of Column chart',
    hAxis: {title: 'Value', titleTextStyle: {color: 'red'}}
  };

  var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));

  chart.draw(data, options);

}
    </script>
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

/assets/bar_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/barchart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1',  Android.getNum1()],
          ['Item 2',  Android.getNum2()],
          ['Item 3',  Android.getNum3()],
          ['Item 4',  Android.getNum4()],
          ['Item 5',  Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Bar chart',
          vAxis: {title: 'Value',  titleTextStyle: {color: 'red'}}
        };

        var chart = new google.visualization.BarChart(document.getElementById('chart_div'));

        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

/assets/histogram.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/histogram-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1', Android.getNum1()],
          ['Item 2', Android.getNum2()],
          ['Item 3', Android.getNum3()],
          ['Item 4', Android.getNum4()],
          ['Item 5', Android.getNum5()]]);

        var options = {
          title: 'Android-er: Google Charts example of Histogram',
          legend: { position: 'none' },
        };

        var chart = new google.visualization.Histogram(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

/assets/line_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/linechart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1',  Android.getNum1()],
          ['Item 2',  Android.getNum2()],
          ['Item 3',  Android.getNum3()],
          ['Item 4',  Android.getNum4()],
          ['Item 5',  Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Line chart'
        };

        var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>

/assets/area_chart.html
<!--ref: https://google-developers.appspot.com/chart/interactive/docs/gallery/areachart-->
<html>
  <head>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Items', 'Value'],
          ['Item 1',  Android.getNum1()],
          ['Item 2',  Android.getNum2()],
          ['Item 3',  Android.getNum3()],
          ['Item 4',  Android.getNum4()],
          ['Item 5',  Android.getNum5()]
        ]);

        var options = {
          title: 'Android-er: Google Charts example of Area chart',
          hAxis: {title: 'Value',  titleTextStyle: {color: '#333'}},
          vAxis: {minValue: 0}
        };

        var chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
    <div id="chart_div" style="width: 100%; height: 100%;"></div>
  </body>
</html>


download filesDownload the files.


Wednesday, August 13, 2014

Display Google Charts (pie chart) on Android WebView

This example show how to use Google Charts to display pie chart on Android WebView. Google chart tools are powerful, simple to use, and free. It not only display a static graphic, but also provide user touch interactive operation, check the video on the bottom.

Display Google Charts (pie chart) displayed Android WebView
We have a MainActivity to collect data from user:
package com.example.androidwebchart;

import android.support.v7.app.ActionBarActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;


public class MainActivity extends ActionBarActivity {
 
 EditText num1, num2, num3, num4, num5;
 Button btnShow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        num1 = (EditText)findViewById(R.id.num1);
        num2 = (EditText)findViewById(R.id.num2);
        num3 = (EditText)findViewById(R.id.num3);
        num4 = (EditText)findViewById(R.id.num4);
        num5 = (EditText)findViewById(R.id.num5);
        btnShow = (Button)findViewById(R.id.show);
        
        btnShow.setOnClickListener(btnShowOnClickListener);
    }
    
    OnClickListener btnShowOnClickListener =
     new OnClickListener(){

   @Override
   public void onClick(View v) {
    Intent intent = new Intent(
     MainActivity.this, 
     ShowWebChartActivity.class);
    
    intent.putExtra("NUM1", getNum(num1));
    intent.putExtra("NUM2", getNum(num2));
    intent.putExtra("NUM3", getNum(num3));
    intent.putExtra("NUM4", getNum(num4));
    intent.putExtra("NUM5", getNum(num5));

    startActivity(intent);
   }
     
    };
    
    private int getNum(EditText editText){
     
     int num = 0;

     String stringNum = editText.getText().toString();
     if(!stringNum.equals("")){
      num = Integer.valueOf(stringNum);
     }
     
     return (num);
    }

}

/res/layout/activity_main.xml, layout of MainActivity.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidwebchart.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    <EditText
        android:id="@+id/num1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number"/>
    <EditText
        android:id="@+id/num2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number"/>
    <EditText
        android:id="@+id/num3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number"/>
    <EditText
        android:id="@+id/num4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number"/>
    <EditText
        android:id="@+id/num5"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="number"/>
    <Button
        android:id="@+id/show"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Show Chart"/>

</LinearLayout>

When User click on the "Show Chart" button, it will start another activity, ShowWebChartActivity.java, and pass user data. ShowWebChartActivity load a WebView with our HTML to display Google Charts with Javascript. We have to implement WebAppInterface, with methods of @JavascriptInterface, getNum1()...getNum5(). It will be called by Javascript inside HTML to retrieve user data.
package com.example.androidwebchart;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;

@SuppressLint("SetJavaScriptEnabled") 
public class ShowWebChartActivity extends ActionBarActivity {
 
 WebView webView;
 int num1, num2, num3, num4, num5;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_webchart);
        
        Intent intent = getIntent();
        num1 = intent.getIntExtra("NUM1", 0);
        num2 = intent.getIntExtra("NUM2", 0);
        num3 = intent.getIntExtra("NUM3", 0);
        num4 = intent.getIntExtra("NUM4", 0);
        num5 = intent.getIntExtra("NUM5", 0);
        
        webView = (WebView)findViewById(R.id.web);
        webView.addJavascriptInterface(new WebAppInterface(), "Android");

        webView.getSettings().setJavaScriptEnabled(true); 
        webView.loadUrl("file:///android_asset/chart.html");
 }

 public class WebAppInterface {

     @JavascriptInterface
  public int getNum1() {
   return num1;
  }
  
  @JavascriptInterface
  public int getNum2() {
   return num2;
  }
  
  @JavascriptInterface
  public int getNum3() {
   return num3;
  }
  
  @JavascriptInterface
  public int getNum4() {
   return num4;
  }
  
  @JavascriptInterface
  public int getNum5() {
   return num5;
  }
 }

}

/res/layout/layout_webchart.xml, layout of ShowWebChartActivity.
<?xml version="1.0" encoding="utf-8"?>
<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:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <WebView
        android:id="@+id/web"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

/assets/chart.html, our HTML to load and display Google Charts. Actually it is modified from Google Quick Start example of pie chart. The main difference is it retrieve user data by calling Android JavascriptInterface methods (getNum1()...getNum5()), instead of fixed data.
<html>
  <head>
    <!--Load the AJAX API-->
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
    
      // Load the Visualization API and the piechart package.
      google.load('visualization', '1.0', {'packages':['corechart']});
      
      // Set a callback to run when the Google Visualization API is loaded.
      google.setOnLoadCallback(drawChart);


      // Callback that creates and populates a data table, 
      // instantiates the pie chart, passes in the data and
      // draws it.
      function drawChart() {

      // Create the data table.
      var data = new google.visualization.DataTable();
      data.addColumn('string', 'ITEM');
      data.addColumn('number', 'VALUE');
      data.addRows([
        ['Item 1', Android.getNum1()],
        ['Item 2', Android.getNum2()],
        ['Item 3', Android.getNum3()], 
        ['Item 4', Android.getNum4()],
        ['Item 5', Android.getNum5()]
      ]);

      // Set chart options
      var options = {'title':'Android-er: Load Google Charts (pie chart) with WebView',
                     'width':600,
                     'height':600};

      // Instantiate and draw our chart, passing in some options.
      var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
      chart.draw(data, options);
    }
    </script>
  </head>

  <body>
 <!--Div that will hold the pie chart-->
    <div id="chart_div" style="width:600; height:600"></div>
  </body>
</html>

Finally, modify AndroidManifest.xml to add <activity> of ShowWebChartActivity, and <uses-permission> of "android.permission.INTERNET".
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidwebchart"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <uses-permission android:name="android.permission.INTERNET"/>

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

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".ShowWebChartActivity"
            android:label="@string/app_name" >
        </activity>
    </application>

</manifest>


download filesDownload the files.

- More Google Charts examples on Android WebView
Capture image generated by Google Charts API
Display Donut Chart on Android WebView, using Google Charts