Android Tutorial - Development : Thread

 Threads Handler Demo

package com.commonsware.android.threads;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
import java.util.concurrent.atomic.AtomicBoolean;

public class HandlerDemo extends Activity {
  ProgressBar bar;
  Handler handler=new Handler() {
    @Override
    public void handleMessage(Message msg) {
      bar.incrementProgressBy(5);
    }
  };
  AtomicBoolean isRunning=new AtomicBoolean(false);
  
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
    bar=(ProgressBar)findViewById(R.id.progress);
  }
  
  public void onStart() {
    super.onStart();
    bar.setProgress(0);
    
    Thread background=new Thread(new Runnable() {
      public void run() {
        try {
          for (int i=0;i<20 && isRunning.get();i++) {
            Thread.sleep(1000);
            handler.sendMessage(handler.obtainMessage());
          }
        }
        catch (Throwable t) {
          // just end the background thread
        }
      }
    });
    
    isRunning.set(true);
    background.start();
  }
  
  public void onStop() {
    super.onStop();
    isRunning.set(false);
  }
}


//res\layout\main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
  <ProgressBar android:id="@+id/progress"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
</LinearLayout>



Using AsyncTask
/***
  Copyright (c) 2008-2009 CommonsWare, LLC
  
  Licensed under the Apache License, Version 2.0 (the "License"); you may
  not use this file except in compliance with the License. You may obtain
  a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

package com.commonsware.android.async;

import android.app.ListActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import java.util.ArrayList;

public class AsyncDemo extends ListActivity {
  private static String[] items={"lorem", "ipsum", "dolor",
                                  "sit", "amet", "consectetuer",
                                  "adipiscing", "elit", "morbi",
                                  "vel", "ligula", "vitae",
                                  "arcu", "aliquet", "mollis",
                                  "etiam", "vel", "erat",
                                  "placerat", "ante",
                                  "porttitor", "sodales",
                                  "pellentesque", "augue",
                                  "purus"};
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    setListAdapter(new ArrayAdapter<String>(this,
                        android.R.layout.simple_list_item_1,
                        new ArrayList()));
    
    new AddStringTask().execute();
  }
  
  class AddStringTask extends AsyncTask<Void, String, Void> {
    @Override
    protected Void doInBackground(Void... unused) {
      for (String item : items) {
        publishProgress(item);
        SystemClock.sleep(200);
      }
      
      return(null);
    }
    
    @Override
    protected void onProgressUpdate(String... item) {
      ((ArrayAdapter)getListAdapter()).add(item[0]);
    }
    
    @Override
    protected void onPostExecute(Void unused) {
      Toast
        .makeText(AsyncDemo.this, "Done!", Toast.LENGTH_SHORT)
        .show();
    }
  }
}



//res\layout\main.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@android:id/list"
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent"
  android:drawSelectorOnTop="false"
/>
Abstract Running Thread
//package cn.edu.hit.voidmain.asmsreplier.pd_factory.threads;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public abstract class RunningThread extends Thread {
  protected Handler handler;
  
  public void setHandler(Handler handler)
  {
    this.handler = handler;
  }
  
  public Handler getHandler()
  {
    return this.handler;
  }
  
  public abstract void doWork();

  @Override
  public void run() {
    super.run();
    
    doWork();
    
    Message m = handler.obtainMessage();
    Bundle b = new Bundle();
    b.putBoolean("result", true);
    m.setData(b);
    handler.sendMessage(m);
  }

}

Sleep current thread

    

public class ServerUtils {
  
  public static void sleep(long time) {
    try {
      Thread.currentThread();
      Thread.sleep(time);
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }
  }
  
  
}

Executors.newFixedThreadPool

    
//package com.myspace.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;

class MSDrawableManager {
    private final Map<String, Drawable> drawableMap;
    private ExecutorService executorService;

    static MSDrawableManager instance;
    
    static public MSDrawableManager getInstance() {
      if (instance == null) {
        synchronized(MSDrawableManager.class) {
          if (instance == null) {
            instance = new MSDrawableManager(); 
          }
        }
      }  
      return instance;
    }
    
    private MSDrawableManager() {
      drawableMap = new HashMap<String, Drawable>();
      executorService = Executors.newFixedThreadPool(2);
    }
    
    public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
      if (drawableMap.containsKey(urlString)) {
        imageView.setImageDrawable(drawableMap.get(urlString));
      }
      
      imageView.setImageDrawable(null);

      final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
          imageView.setImageDrawable((Drawable) message.obj);
        }
      };

      executorService.execute(new Runnable() {
        public void run() {
          Drawable drawable = fetchDrawable(urlString);
          Message message = handler.obtainMessage(1, drawable);
          handler.sendMessage(message);
        }
      });
    }
    
    public Drawable fetchDrawable(String urlString) {
      if (drawableMap.containsKey(urlString)) {
        return drawableMap.get(urlString);
      }

      try {
        InputStream is = fetch(urlString);
        Drawable drawable = Drawable.createFromStream(is, "src");
        drawableMap.put(urlString, drawable);
        return drawable;
      } catch (Exception e) {
        return null; 
      }
    }

    private InputStream fetch(String urlString) throws MalformedURLException, IOException {
      DefaultHttpClient httpClient = new DefaultHttpClient();
      HttpGet request = new HttpGet(urlString);
      HttpResponse response = httpClient.execute(request);
      return response.getEntity().getContent();
    }
}

Counting Thread

    
//package com.postpc.easyrider.utils;

class CountingThread extends Thread {
  private int _initialCount;
  private int _millisBetweenCount;
  private CountingListener _listener;
  private boolean _stopCounting = false;
  private boolean _hardAbort = false;
  

  public CountingThread(CountingListener listener, int initialCount, int millisBetweenCount) {
    _listener = listener;
    _initialCount = initialCount;
    _millisBetweenCount = millisBetweenCount;
  }
  
  @Override
  public void run() {
    int counter = _initialCount;
    
    _listener.onCountBegin(counter);
    
    while (!_stopCounting && counter > 0) {
      try {
        Thread.sleep(_millisBetweenCount);
      } catch (InterruptedException e) {
        // someone wants us out
        _listener.onCountAborted(counter);
        
        return;
      }
      
      counter--;
      _listener.onCount(counter);
    }
    
    if (_stopCounting) {
      if (!_hardAbort) {
        _listener.onCountAborted(counter);  
      }
    } else {
      _listener.onCountComplete();  
    }
  }

  public void abort() {
    _stopCounting = true;
    
    this.interrupt();
  }
  

  public void hardAbort() {
    _hardAbort = true;
    
    abort();
  }
}

 interface CountingListener {

  public void onCountBegin(int counter);
  

  public void onCount(int counter);

  public void onCountComplete();

  public void onCountAborted(int counter);
}

Task Queue

//package dk.itu.nai.util;

import java.util.LinkedList;

import android.util.Log;



class TaskQueue {
     private LinkedList<Runnable> tasks;
     private Thread thread;
     private boolean running;
     private Runnable internalRunnable;
     
     private final String ME = "TaskQueue";
    
     private class InternalRunnable implements Runnable {
       public void run() {
         internalRun();
       }
     }
    
     public TaskQueue() {
       tasks = new LinkedList<Runnable>();
       internalRunnable = new InternalRunnable();
     }
    
     public void start() {
       if (!running) {
         thread = new Thread(internalRunnable);
         thread.setDaemon(true);
         running = true;
         thread.start();
       }
     }
    
     public void stop() {
       running = false;
     }
   
    public void addTask(Runnable task) {
      Log.d(ME, "addTask");
       synchronized(tasks) {
           tasks.addLast(task);
           tasks.notify(); // notify any waiting threads           
       }
     }
    
     private Runnable getNextTask() {
       Log.d(ME, "getNextTask");
       synchronized(tasks) {
         if (tasks.isEmpty()) {
           try {
             tasks.wait();
           } catch (InterruptedException e) {
             Log.e(ME, "Task interrupted", e);
             stop();
           }
         }
         return tasks.removeFirst();
       }
     }
    
    
     private void internalRun() {
       while(running) {
         Runnable task = getNextTask();
         try {
           task.run();
           Thread.yield();
         } catch (Throwable t) {
           Log.e(ME, "Task threw an exception", t);
         }
       }
     }
  }

Delay Task

//package org.comet4j.core.util;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 * ???????????????????????????????????????????????????taskId?????
 * @author xiaojinghai
 * @date 2011-7-25
 */

public class DelayTask {

  private final int cpuCoreNumber = Runtime.getRuntime().availableProcessors();
  private final ScheduledExecutorService scheduler;
  private final Map<String, ScheduledFuture<Runnable>> taskHandles = new ConcurrentHashMap<String, ScheduledFuture<Runnable>>();

  public DelayTask() {
    scheduler = Executors.newScheduledThreadPool(cpuCoreNumber);
  }

  public DelayTask(int cpuCoreNumber) {
    scheduler = Executors.newScheduledThreadPool(cpuCoreNumber);
  }



  @SuppressWarnings("unchecked")
  public void delay(String taskId, Runnable task, long delay, TimeUnit unit) {
    ScheduledFuture<Runnable> taskHandle = taskHandles.get(taskId);
    if (taskHandle == null || taskHandle.isDone()) {
      taskHandle = (ScheduledFuture<Runnable>) scheduler.schedule(task, delay, unit);
    } else {
      taskHandle.cancel(true);
      taskHandle = (ScheduledFuture<Runnable>) scheduler.schedule(task, delay, unit);
    }
    taskHandles.put(taskId, taskHandle);
  }

  /**
   * ???????????
   * @param taskId ??Id
   */

  public void cancel(String taskId) {
    ScheduledFuture<Runnable> taskHandle = taskHandles.get(taskId);
    if (taskHandle != null && !taskHandle.isDone()) {
      taskHandle.cancel(true);
    }
  }

  /**
   * ???????????
   */

  public void cancelAllTask() {
    for (String taskId : taskHandles.keySet()) {
      ScheduledFuture<Runnable> taskHandle = taskHandles.get(taskId);
      if (taskHandle != null && !taskHandle.isDone()) {
        taskHandle.cancel(true);
      }
    }
  }

  public void shutdown() {
    scheduler.shutdown();
  }

}










































Android Tutorial - Development : random

Random Alphabet Maker

    
//package com.ou.android.game.common;

import java.util.ArrayList;

class RandomAlphabetMaker {

  private ArrayList<String> mList;
  int mCount;

  public RandomAlphabetMaker(int count) {
    mCount = count;
    init();
  }

  private void init() {
    mList = new ArrayList<String>();
    char a = 'A';
    for (int i = 0; i < mCount; i++) {
      char item = (char) (a + i);
      String s = Character.toString(item);
      mList.add(s);
    }
  }

  public ArrayList<String> getRandomList() {
    ArrayList<String> ret = new ArrayList<String>();
    if (mList.size() == 0) {
      init();
    }
    while (mList.size() > 0) {
      int index = (int) (Math.random() * 100) % mList.size();
      ret.add(mList.get(index));
      mList.remove(index);
    }
    return ret;
  }
} 

Next random Int

    
//package org.expressme.wireless.game;

import java.util.Random;

class Main {

  private static final Random RANDOM = new Random();

  /**
   * Generate random integer between 0(include) and max(exclude).
   */
  public static int nextRandomInt(int max) {
    int n = RANDOM.nextInt();
    return (n < 0 ? -n : n) % max;
  }

  /**
   * Generate random integer between 0(include) and Integer.MAX_VALUE.
   */
  public static int nextRandomInt() {
    int n = RANDOM.nextInt();
    return n < 0 ? -n : n;
  }
} 

Random Xor Obfuscator

    
//package se.ramfelt.psnfriends.util;

import java.util.Random;
import java.util.StringTokenizer;

public class RandomXorObfuscator {

  private final long seed;

  public RandomXorObfuscator(long seed) {
    this.seed = seed;
  }

  public String perform(String text) {
    if (text == null) {
      return null;
    }
    Random random = new Random(seed);
    StringBuilder builder = new StringBuilder(text.length());
    char[] chars = text.toCharArray();
    for (int i = 0; i < chars.length; i++) {
      builder.append((int)(chars[i] ^ random.nextInt()));
      builder.append(',');
    }
    return builder.toString();
  }
  
  public String reverse(String text) {
    if (text == null) {
      return null;
    }
    StringTokenizer tokenizer = new StringTokenizer(text, ",");
    StringBuilder builder = new StringBuilder();
    Random random = new Random(seed);
    while (tokenizer.hasMoreTokens()) {
      builder.append((char)(Integer.parseInt(tokenizer.nextToken()) ^ random.nextInt()));
    }
    return builder.toString();
  }
} 

returns a random number among { 0 to count-1 }

    
import java.util.Calendar;
import java.util.Random;

class CommonUtil {
  
  private static Random random = new Random(Calendar.getInstance().getTimeInMillis());
  
  /**
   * 
   * @param count
   * @return returns a random number among { 0 to count-1 }
   */
  public static short getRandomIndex(short count){
    int randomIndex = random.nextInt();
    short resultIndex = (short) (randomIndex % count);
    if(resultIndex < 0){
      resultIndex += count;
    }
    return resultIndex;
  }

}

 Random Generator

    
//package br.com.tecnove.random.android.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;

public class RandomGenerator {

  private static final Random r = new Random();


  public static int generateFromRange(int min, int max) {
    // swap values if they come in the wrong order
    if (min > max) {
      int aux = min;
      min = max;
      max = aux;
    }
    int i = max - min;
    int x = r.nextInt(i + 1);
    return x + min;
  }

  public static String generateFromStringArray(String[] input) {
    int i = generateFromRange(0, input.length - 1);
    return input[i];
  }


  public static String generateFromStringCollection(Collection<String> input) {
    return generateFromStringArray((String[]) input.toArray());
  }


  public static char generateLetter() {
    return (char) generateFromRange((int) 'A', (int) 'Z');
  }

  public static List<Integer> generateLottery(Integer maxRange, Integer numbersToGenerate) {
    List<Integer> numbersGenerated = new ArrayList<Integer>();
    for (int c = 0; c < numbersToGenerate; c++) {
      int nGenerated = 0;
      do {
        nGenerated = r.nextInt(maxRange);
        // adding +1 to make the int start at 1 and the maxRange be included in the sorted values
        nGenerated++;
        // if the number is allready on the list, sort a new number
      } while (numbersGenerated.contains(nGenerated));
      numbersGenerated.add(nGenerated);
    }
    return numbersGenerated;
  }
  

  public static String generateFromString(String valor) {
    // the input must be like: curitiba/fortaleza/google/facebook/android/motorola
    String[] vetor = valor.split("/");
    String outValue = "";
    if (vetor.length>0){
      outValue = vetor[r.nextInt(vetor.length)];
    }
    return outValue;
  }
}

Get Random Index

    
import android.graphics.Paint;

class Main {
  public static int GetRandomIndex(int min, int max)
  {
    return (int) (Math.random() * (max - min + 1)) + min;
  }

}

Run System Command

//package com.googlecode.gogodroid;

import java.io.IOException;
import java.io.OutputStream;

import android.util.Log;

class Utils {
    
  private static final String LOG_TAG = "Gogoc";


    public static void runCommand(String command) {
      try {
        Process process = Runtime.getRuntime().exec("sh");
        //process = Runtime.getRuntime().exec("sh");
        OutputStream os = process.getOutputStream();
        Log.d(LOG_TAG, "runCommand() cmd=" + command );
        writeLine( os, command );
        os.flush();
        }
      catch ( IOException e ) {
        e.printStackTrace();
      }
    }


    public static void runSuCommand(String sucommand) {
      try {
        Process process = Runtime.getRuntime().exec("su -c sh");
        //process = Runtime.getRuntime().exec("sh");
        OutputStream os = process.getOutputStream();
        Log.d(LOG_TAG, "runSuCommand() cmd=" + sucommand );
        writeLine( os, sucommand );
        os.flush();
        }
      catch ( IOException e ) {
        e.printStackTrace();
      }
    }
    
    
  private static void writeLine(OutputStream os, String value) throws IOException
  {
    String line = value + "\n";
    os.write( line.getBytes() );
  }
}

Exec And Wait

//package org.zenthought.flashrec;

import java.io.IOException;

import android.util.Log;

class Util {
    public static boolean execAndWait(String[] args) {
        try {
            Process p = Runtime.getRuntime().exec(args);
            while (true) try {
                int code = p.waitFor();
                if (code != 0) { Log.d("FlashRec", String.format("%s exited with code %d", args[0], code)); return false; }
                return true;
            } catch (InterruptedException e) {
                e.printStackTrace();
                continue;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }
}

   

Get Api Level

//package com.alfray.brighteriffic;

import android.os.Build;
import android.os.Build.VERSION;

class Utils {

    private static int sApiLevel = 0;

    /**
     * Return {@link VERSION#SDK} as an int.
     * Value is cached locally.
     */
    public static int getApiLevel() {
        if (sApiLevel == 0) {
            try {
                // SDK_INT only exists since API 4 so let's use the string version.
                sApiLevel = Integer.parseInt(Build.VERSION.SDK);
            } catch (Exception e) {
                // This app doesn't run below 3 anyway
                sApiLevel = 3;
            }
        }

        return sApiLevel;
    }

}

Check For Installed App

    
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;

class Main {
  public static boolean checkForInstalledApp(Context ctx, String pkgName) {
    try {
      PackageManager pm = ctx.getPackageManager();
      pm.getPackageInfo(pkgName, 0);
      // Log.d(TAG, pkgString + " is installed");
      return true;
    } catch (NameNotFoundException e) {
      // Log.d(TAG, pkgString + " is not installed");
    }
    return false;
  }

}

Get App Name

    
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;

class Main {

  public static String getAppName(Context ctx, String pkgName) {
    try {
      PackageManager pm = ctx.getPackageManager();
      ApplicationInfo appInfo = pm.getApplicationInfo(pkgName, 0);
      String label = pm.getApplicationLabel(appInfo).toString();
      return label;
    } catch (NameNotFoundException e) {
      return "";
    }
  }
}

Get Process ID with shell command and read by Java code

    
//package org.codeandroid.vpnc_frontend;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;

import android.util.Log;

class Util
{

  private static final String LOG_TAG = "VPN_Connections";
  public static final int DISCONNECT_NOTIFICATION = 1;
  private static final int pidColumn = getPidColumn();

  public static int getPidColumn()
  {
    try
    {
      Process psProcess = Runtime.getRuntime().exec( "sh" );
      OutputStream os = psProcess.getOutputStream();
      InputStream is = psProcess.getInputStream();
      writeLine( os, null, "ps | grep PID" );
      writeLine( os, null, "exit" );
      try
      {
        psProcess.waitFor();
      }
      catch( InterruptedException interruptedException )
      {
        Log.e( LOG_TAG, "While trying to read process id", interruptedException );
        return -1;
      }
      String headerLine = readString( is, null, false );
      Log.d( LOG_TAG, "Read PS header line as " + headerLine );
      if( headerLine == null || headerLine.trim().length() == 0 )
      {
        Log.e( LOG_TAG, "Attempt to do a PS did not return anything" );
        return -1;
      }
      else
      {
        StringTokenizer tokenizer = new StringTokenizer( headerLine, " ", false );
        int columnCount = tokenizer.countTokens();
        for( int index = 0; index < columnCount; index++ )
        {
          if( "PID".equals( tokenizer.nextToken() ) )
          {
            Log.d( LOG_TAG, "PID is in column #" + index );
            return index;
          }
        }
        return -1;
      }
    }
    catch( IOException e )
    {
      Log.e( LOG_TAG, "While trying to read process id", e );
      return -1;
    }
  }

  public static int getProcessId()
  {
    if( pidColumn == -1 )
    {
      return -1;
    }
    try
    {
      Process psProcess = Runtime.getRuntime().exec( "sh" );
      OutputStream os = psProcess.getOutputStream();
      InputStream is = psProcess.getInputStream();
      writeLine( os, null, "ps | grep 'vpnc$'" );
      writeLine( os, null, "exit" );
      try
      {
        psProcess.waitFor();
      }
      catch( InterruptedException interruptedException )
      {
        Log.e( LOG_TAG, "While trying to read process id", interruptedException );
        return 0;
      }
      String pidStringLine = readString( is, null, false );
      Log.d( LOG_TAG, "Read vpnc process line as " + pidStringLine );
      if( pidStringLine == null || pidStringLine.trim().length() == 0 )
      {
        Log.d( LOG_TAG, "Attempt to read vpnc process id did not return anything" );
        return -1;
      }
      else
      {
        StringTokenizer tokenizer = new StringTokenizer( pidStringLine, " ", false );
        String pidString = tokenizer.nextToken();
        for( int index = 0; index < pidColumn; index++ )
        {
          pidString = tokenizer.nextToken();
        }
        Log.d( LOG_TAG, "Read vpnc process id as " + pidString );
        try
        {
          return Integer.parseInt( pidString );
        }
        catch( NumberFormatException e )
        {
          Log.w( LOG_TAG, "Could not parse process id of " + pidString, e );
          return 0;
        }
      }
    }
    catch( IOException e )
    {
      Log.e( LOG_TAG, "While trying to read process id", e );
      return 0;
    }
  }

  public static String readString(InputStream is, PrintWriter logWriter, boolean block) throws IOException
  {
    if( !block && is.available() == 0 )
    {
      //Caller doesn't want to wait for data and there isn't any available right now
      return null;
    }
    byte firstByte = (byte)is.read(); //wait till something becomes available
    int available = is.available();
    byte[] characters = new byte[available + 1];
    characters[0] = firstByte;
    is.read( characters, 1, available );
    String string = new String( characters );
    if( logWriter != null )
    {
      logWriter.println( string );
    }
    return string;
  }

  public static void writeLine(OutputStream os, PrintWriter logWriter, String value) throws IOException
  {
    String line = value + "\n";
    os.write( line.getBytes() );
    if( logWriter != null )
    {
      logWriter.println( value );
    }
  }

  public static void debug(String msg)
  {
    Log.d( LOG_TAG, msg );
  }

  public static void debug(String msg, Throwable throwable)
  {
    Log.d( LOG_TAG, msg, throwable );
  }

  public static void info(String msg)
  {
    Log.i( LOG_TAG, msg );
  }

  public static void info(String msg, Throwable throwable)
  {
    Log.i( LOG_TAG, msg, throwable );
  }

  public static void warn(String msg)
  {
    Log.w( LOG_TAG, msg );
  }

  public static void warn(String msg, Throwable throwable)
  {
    Log.w( LOG_TAG, msg, throwable );
  }

  public static void error(String msg)
  {
    Log.e( LOG_TAG, msg );
  }

  public static void error(String msg, Throwable throwable)
  {
    Log.e( LOG_TAG, msg, throwable );
  }

  public static void printLog(int priority, String msg)
  {
    Log.println( priority, LOG_TAG, msg );
  }
}

decode UTF8 to char

 

class Main {
    public static final String HEX_DIGITS = "0123456789ABCDEF";

    public static char decodeUTF8(String src) {
        if (src == null) {
            throw new IllegalArgumentException("Malformed \\uxxxx encoding.");
        }

        if (!(src.startsWith("\\u") && src.length() <= 6)) {
            throw new IllegalArgumentException("Malformed \\uxxxx encoding.");
        }

        char[] sources = src.substring(2).toCharArray();
        char res = 0;
        for (char nextChar : sources) {
            int digit = HEX_DIGITS.indexOf(Character.toUpperCase(nextChar));
            res = (char) (res * 16 + digit);
        }
        return res;
    }

}

decode UTF8 to String

 
class Main {

  public static final String HEX_DIGITS = "0123456789ABCDEF";

  public static char decodeUTF8(String src) {
    if (src == null) {
      throw new IllegalArgumentException("Malformed \\uxxxx encoding.");
    }

    if (!(src.startsWith("\\u") && src.length() <= 6)) {
      throw new IllegalArgumentException("Malformed \\uxxxx encoding.");
    }

    char[] sources = src.substring(2).toCharArray();
    char res = 0;
    for (char nextChar : sources) {
      int digit = HEX_DIGITS.indexOf(Character.toUpperCase(nextChar));
      res = (char) (res * 16 + digit);
    }
    return res;
  }

  public static String decodeUTF8String(String src) {
    StringBuilder sb = new StringBuilder();
    char[] sources = src.toCharArray();
    for (int i = 0; i < sources.length; i++) {
      if (sources[i] == '\\' && i < sources.length - 5
          && sources[i + 1] == 'u') {
        String utf8 = "" + sources[i++] + sources[i++] + sources[i++]
            + sources[i++] + sources[i++] + sources[i];
        sb.append(decodeUTF8(utf8));
        i = i + 5;
      } else {
        sb.append(sources[i]);
      }
    }
    return sb.toString();
  }

}

implements InputFilter

 
//package divestoclimb.util;

import android.text.InputFilter;
import android.text.Spanned;

class ValidFilenameFilter implements InputFilter {

  public CharSequence filter(CharSequence source, int start, int end,
      Spanned dest, int dstart, int dend) {
    String valid = "";
    for(int i = start; i < end; i++) {
      char c = source.charAt(i);
      // These characters are the ones Windows doesn't
      // like, which appears to be the most restrictive
      // set. http://support.microsoft.com/kb/177506
      switch(c) {
      case '/':
      case '\\':
      case ':':
        c = '-';
        break;
      case '"':
        c = '\'';
        break;
      case '*':
      case '?':
      case '<':
      case '>':
      case '|':
        c = '_';
      }
      valid = valid.concat(String.valueOf(c));
    }
    return valid;
  }

}
UTF 2 GBUtil
public abstract class UTF2GBUtil {

    public static String covert(String src) {
        StringBuffer sb = new StringBuffer();
        char[] chars = src.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] == '\\' && chars[i + 1] == 'u') {
                int one = h(chars[i + 2]) * 4096;
                if (-1 == one) {
                    sb.append(chars[i]);
                    continue;
                }
                int two = h(chars[i + 3]) * 256;
                if (-1 == two) {
                    sb.append(chars[i]);
                    continue;
                }
                int three = h(chars[i + 4]) * 16;
                if (-1 == three) {
                    sb.append(chars[i]);
                    continue;
                }
                int four = h(chars[i + 5]);
                if (-1 == four) {
                    sb.append(chars[i]);
                    continue;
                }
                int count = one + two + three + four;
                sb.append((char) count);
                i += 5;
                continue;
            }
            sb.append(chars[i]);
        }
        return sb.toString();
    }

    private static int h(char c) {
        if (c > 47 && c < 58) {
            return c - 48;
        } else if (c > 64 && c < 71) {
            return c - 55;
        } else if (c > 96 && c < 103) {
            return c - 87;
        }
        return -1;
    }
}

Load UTF8 encoded file to String

 

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

class Utils {

  public static String loadFile(String fileName) throws IOException {
    StringBuffer buffer = new StringBuffer();
    FileInputStream fis = new FileInputStream(fileName);
    InputStreamReader isr = new InputStreamReader(fis, "UTF8");
    Reader in = new BufferedReader(isr);
    int ch;
    while ((ch = in.read()) > -1) {
      buffer.append((char) ch);
    }
    in.close();
    return buffer.toString();
  }

}

UTF8 to Byte Array

 
//package org.bouncycastle.util;

import java.io.ByteArrayOutputStream;
import java.util.Vector;

public final class Strings
{
    public static String fromUTF8ByteArray(byte[] bytes)
    {
        int i = 0;
        int length = 0;

        while (i < bytes.length)
        {
            length++;
            if ((bytes[i] & 0xf0) == 0xf0)
            {
                // surrogate pair
                length++;
                i += 4;
            }
            else if ((bytes[i] & 0xe0) == 0xe0)
            {
                i += 3;
            }
            else if ((bytes[i] & 0xc0) == 0xc0)
            {
                i += 2;
            }
            else
            {
                i += 1;
            }
        }

        char[] cs = new char[length];

        i = 0;
        length = 0;

        while (i < bytes.length)
        {
            char ch;

            if ((bytes[i] & 0xf0) == 0xf0)
            {
                int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i+1] & 0x3F) << 12) | ((bytes[i+2] & 0x3F) << 6) | (bytes[i+3] & 0x3F);
                int U = codePoint - 0x10000;
                char W1 = (char)(0xD800 | (U >> 10));
                char W2 = (char)(0xDC00 | (U & 0x3FF));
                cs[length++] = W1;
                ch = W2;
                i += 4;
            }
            else if ((bytes[i] & 0xe0) == 0xe0)
            {
                ch = (char)(((bytes[i] & 0x0f) << 12)
                        | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f));
                i += 3;
            }
            else if ((bytes[i] & 0xd0) == 0xd0)
            {
                ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
                i += 2;
            }
            else if ((bytes[i] & 0xc0) == 0xc0)
            {
                ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
                i += 2;
            }
            else
            {
                ch = (char)(bytes[i] & 0xff);
                i += 1;
            }

            cs[length++] = ch;
        }

        return new String(cs);
    }
    
    public static byte[] toUTF8ByteArray(String string)
    {
        return toUTF8ByteArray(string.toCharArray());
    }

    public static byte[] toUTF8ByteArray(char[] string)
    {
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        char[] c = string;
        int i = 0;

        while (i < c.length)
        {
            char ch = c[i];

            if (ch < 0x0080)
            {
                bOut.write(ch);
            }
            else if (ch < 0x0800)
            {
                bOut.write(0xc0 | (ch >> 6));
                bOut.write(0x80 | (ch & 0x3f));
            }
            // surrogate pair
            else if (ch >= 0xD800 && ch <= 0xDFFF)
            {
                // in error - can only happen, if the Java String class has a
                // bug.
                if (i + 1 >= c.length)
                {
                    throw new IllegalStateException("invalid UTF-16 codepoint");
                }
                char W1 = ch;
                ch = c[++i];
                char W2 = ch;
                // in error - can only happen, if the Java String class has a
                // bug.
                if (W1 > 0xDBFF)
                {
                    throw new IllegalStateException("invalid UTF-16 codepoint");
                }
                int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000;
                bOut.write(0xf0 | (codePoint >> 18));
                bOut.write(0x80 | ((codePoint >> 12) & 0x3F));
                bOut.write(0x80 | ((codePoint >> 6) & 0x3F));
                bOut.write(0x80 | (codePoint & 0x3F));
            }
            else
            {
                bOut.write(0xe0 | (ch >> 12));
                bOut.write(0x80 | ((ch >> 6) & 0x3F));
                bOut.write(0x80 | (ch & 0x3F));
            }

            i++;
        }
        
        return bOut.toByteArray();
    }
    
    /**
     * A locale independent version of toUpperCase.
     * 
     * @param string input to be converted
     * @return a US Ascii uppercase version
     */
    public static String toUpperCase(String string)
    {
        boolean changed = false;
        char[] chars = string.toCharArray();
        
        for (int i = 0; i != chars.length; i++)
        {
            char ch = chars[i];
            if ('a' <= ch && 'z' >= ch)
            {
                changed = true;
                chars[i] = (char)(ch - 'a' + 'A');
            }
        }
        
        if (changed)
        {
            return new String(chars);
        }
        
        return string;
    }
    
    /**
     * A locale independent version of toLowerCase.
     * 
     * @param string input to be converted
     * @return a US ASCII lowercase version
     */
    public static String toLowerCase(String string)
    {
        boolean changed = false;
        char[] chars = string.toCharArray();
        
        for (int i = 0; i != chars.length; i++)
        {
            char ch = chars[i];
            if ('A' <= ch && 'Z' >= ch)
            {
                changed = true;
                chars[i] = (char)(ch - 'A' + 'a');
            }
        }
        
        if (changed)
        {
            return new String(chars);
        }
        
        return string;
    }

    public static byte[] toByteArray(char[] chars)
    {
        byte[] bytes = new byte[chars.length];

        for (int i = 0; i != bytes.length; i++)
        {
            bytes[i] = (byte)chars[i];
        }

        return bytes;
    }

    public static byte[] toByteArray(String string)
    {
        byte[] bytes = new byte[string.length()];

        for (int i = 0; i != bytes.length; i++)
        {
            char ch = string.charAt(i);

            bytes[i] = (byte)ch;
        }

        return bytes;
    }

    public static String[] split(String input, char delimiter)
    {
        Vector           v = new Vector();
        boolean moreTokens = true;
        String subString;

        while (moreTokens)
        {
            int tokenLocation = input.indexOf(delimiter);
            if (tokenLocation > 0)
            {
                subString = input.substring(0, tokenLocation);
                v.addElement(subString);
                input = input.substring(tokenLocation + 1);
            }
            else
            {
                moreTokens = false;
                v.addElement(input);
            }
        }

        String[] res = new String[v.size()];

        for (int i = 0; i != res.length; i++)
        {
            res[i] = (String)v.elementAt(i);
        }
        return res;
    }
}

Parse Json string

   



package app.test;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import org.json.JSONObject;
import org.json.JSONException;

public class Test extends Activity {
    private static final String JSON_STRING =
        "{\"person\":{\"name\":\"A\",\"age\":30,\"children\":[{\"name\":\"B\",\"age\":5}," + "\"name\":\"C\",\"age\":7},{\"name\":\"D\",\"age\":9}]}}";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        TextView line1 = (TextView)findViewById(R.id.line1);
        TextView line2 = (TextView)findViewById(R.id.line2);
        TextView line3 = (TextView)findViewById(R.id.line3);
        try {
            JSONObject person = (new JSONObject(JSON_STRING)).getJSONObject("person");
            String name = person.getString("name");
            line1.setText("This person's name is " + name);
            line2.setText(name + " is " + person.getInt("age") + " years old.");
            line3.setText(name + " has " + person.getJSONArray("children").length()
                + " children.");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}
//main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical">
  <TextView
    android:id="@+id/line1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
  />
  <TextView
    android:id="@+id/line2"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
  />
  <TextView
    android:id="@+id/line3"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"T
  />
</LinearLayout>

Upload Image to Flickr with JSON

   

package app.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class Test extends Activity {
  String API_KEY = "YOUR_API_KEY";
  FlickrPhoto[] photos;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    HttpClient httpclient = new DefaultHttpClient();
    HttpGet httpget = new HttpGet("http://api.flickr.com/services/rest/?method=flickr.photos.search&tags=yourTag&format=json&api_key="+ API_KEY + "&per_page=5&nojsoncallback=1");
    HttpResponse response;
    try {
      response = httpclient.execute(httpget);
      HttpEntity entity = response.getEntity();
      if (entity != null) {
        InputStream inputstream = entity.getContent();
        BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(inputstream));
        StringBuilder stringbuilder = new StringBuilder();
        String currentline = null;
        try {
          while ((currentline = bufferedreader.readLine()) != null) {
            stringbuilder.append(currentline + "\n");
          }
        } catch (IOException e) {
          e.printStackTrace();
        }
        String result = stringbuilder.toString();

        JSONObject thedata = new JSONObject(result);
        JSONObject thephotosdata = thedata.getJSONObject("photos");
        JSONArray thephotodata = thephotosdata.getJSONArray("photo");
        photos = new FlickrPhoto[thephotodata.length()];
        for (int i = 0; i < thephotodata.length(); i++) {
          JSONObject photodata = thephotodata.getJSONObject(i);
          photos[i] = new FlickrPhoto(photodata.getString("id"),
              photodata.getString("owner"), photodata
                  .getString("secret"), photodata
                  .getString("server"), photodata
                  .getString("title"), photodata
                  .getString("farm"));
        }
        inputstream.close();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

    ListView listView = (ListView) this.findViewById(R.id.ListView);
    listView.setAdapter(new FlickrGalleryAdapter(this, photos));
  }
}

class FlickrGalleryAdapter extends BaseAdapter {
  private Context context;
  private FlickrPhoto[] photos;

  LayoutInflater inflater;

  public FlickrGalleryAdapter(Context _context, FlickrPhoto[] _items) {
    context = _context;
    photos = _items;

    inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  }

  public int getCount() {
    return photos.length;
  }

  public Object getItem(int position) {
    return photos[position];
  }

  public long getItemId(int position) {
    return position;
  }

  public View getView(int position, View convertView, ViewGroup parent) {

    View photoRow = inflater.inflate(R.layout.row, null);

    ImageView image = (ImageView) photoRow.findViewById(R.id.ImageView);
    image.setImageBitmap(imageFromUrl(photos[position].makeURL()));

    TextView imagevideoTitle = (TextView) photoRow
        .findViewById(R.id.TextView);
    imagevideoTitle.setText(photos[position].title);
    return photoRow;
  }

  public Bitmap imageFromUrl(String url) {
    Bitmap bitmapImage;

    URL imageUrl = null;
    try {
      imageUrl = new URL(url);
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
    try {
      HttpURLConnection httpConnection = (HttpURLConnection) imageUrl
          .openConnection();
      httpConnection.setDoInput(true);
      httpConnection.connect();
      InputStream is = httpConnection.getInputStream();

      bitmapImage = BitmapFactory.decodeStream(is);
    } catch (IOException e) {
      e.printStackTrace();
      bitmapImage = Bitmap.createBitmap(10, 10,
          Bitmap.Config.ARGB_8888);
    }
    return bitmapImage;
  }
}

class FlickrPhoto {
  String id;
  String owner;
  String secret;
  String server;
  String title;
  String farm;

  public FlickrPhoto(String _id, String _owner, String _secret,
      String _server, String _title, String _farm) {
    id = _id;
    owner = _owner;
    secret = _secret;
    server = _server;
    title = _title;
    farm = _farm;
  }
  public String makeURL() {
    return "http://farm" + farm + ".static.flickr.com/" + server + "/"+ id + "_" + secret + "_m.jpg";
  }
}


//main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ListView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/ListView"></ListView>
</LinearLayout>


//row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
    <ImageView android:id="@+id/ImageView" android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageView>
    <TextView android:text="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/TextView"></TextView>
</LinearLayout>

Flickr JSON Location

   
package app.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class Test extends Activity implements LocationListener {

  public static final String API_KEY = "YOUR_API_KEY";

  FlickrPhoto[] photos;
  TextView tv;
  LocationManager lm;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    tv = (TextView) findViewById(R.id.TextView);
    tv.setText("Looking Up Location");

    lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 60000l,
        500.0f, this);
  }

  public void onPause() {
    super.onPause();
    lm.removeUpdates(this);
  }

  public void onLocationChanged(Location location) {
    tv.setText(location.getLatitude() + " " + location.getLongitude());
    Log.v("LOCATION", "onLocationChanged: lat=" + location.getLatitude()
        + ", lon=" + location.getLongitude());

    HttpClient httpclient = new DefaultHttpClient();

    String url = "http://api.flickr.com/services/rest/?method=flickr.photos.search&tags= dog,halloween&format=json&api_key="
        + API_KEY
        + "&per_page=5&nojsoncallback=1&accuracy=6&lat="
        + location.getLatitude() + "&lon=" + location.getLongitude();
    HttpGet httpget = new HttpGet(url);

    HttpResponse response;
    try {
      response = httpclient.execute(httpget);
      HttpEntity entity = response.getEntity();

      if (entity != null) {

        InputStream inputstream = entity.getContent();

        BufferedReader bufferedreader = new BufferedReader(
            new InputStreamReader(inputstream));
        StringBuilder stringbuilder = new StringBuilder();

        String currentline = null;
        try {
          while ((currentline = bufferedreader.readLine()) != null) {
            stringbuilder.append(currentline + "\n");
          }
        } catch (IOException e) {
          e.printStackTrace();
        }
        String result = stringbuilder.toString();

        JSONObject thedata = new JSONObject(result);
        JSONObject thephotosdata = thedata.getJSONObject("photos");
        JSONArray thephotodata = thephotosdata.getJSONArray("photo");

        photos = new FlickrPhoto[thephotodata.length()];
        for (int i = 0; i < thephotodata.length(); i++) {
          JSONObject photodata = thephotodata.getJSONObject(i);
          photos[i] = new FlickrPhoto(photodata.getString("id"),
              photodata.getString("owner"), photodata
                  .getString("secret"), photodata
                  .getString("server"), photodata
                  .getString("title"), photodata
                  .getString("farm"));
          Log.v("URL", photos[i].makeURL());
        }

        inputstream.close();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

    ListView listView = (ListView) this.findViewById(R.id.ListView);
    listView.setAdapter(new FlickrGalleryAdapter(this, photos));
  }

  public void onProviderDisabled(String provider) {
  }

  public void onProviderEnabled(String provider) {
  }

  public void onStatusChanged(String provider, int status, Bundle extras) {
  }
}

class FlickrGalleryAdapter extends BaseAdapter {
  private Context context;
  private FlickrPhoto[] photos;

  LayoutInflater inflater;

  public FlickrGalleryAdapter(Context _context, FlickrPhoto[] _items) {
    context = _context;
    photos = _items;

    inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  }

  public int getCount() {
    return photos.length;
  }

  public Object getItem(int position) {
    return photos[position];
  }

  public long getItemId(int position) {
    return position;
  }

  public View getView(int position, View convertView, ViewGroup parent) {
    View videoRow = inflater.inflate(R.layout.row, null);

    ImageView image = (ImageView) videoRow.findViewById(R.id.ImageView);
    image.setImageBitmap(imageFromUrl(photos[position].makeURL()));

    TextView videoTitle = (TextView) videoRow
        .findViewById(R.id.TextView);
    videoTitle.setText(photos[position].title);
    return videoRow;
  }

  public Bitmap imageFromUrl(String url) {
    Bitmap bitmapImage;

    URL imageUrl = null;
    try {
      imageUrl = new URL(url);
    } catch (MalformedURLException e) {
      e.printStackTrace();
    }
    try {
      HttpURLConnection httpConnection = (HttpURLConnection) imageUrl
          .openConnection();
      httpConnection.setDoInput(true);
      httpConnection.connect();
      int length = httpConnection.getContentLength();
      InputStream is = httpConnection.getInputStream();

      bitmapImage = BitmapFactory.decodeStream(is);
    } catch (IOException e) {
      e.printStackTrace();
      bitmapImage = Bitmap.createBitmap(10, 10,
          Bitmap.Config.ARGB_8888);
    }
    return bitmapImage;
  }
}

class FlickrPhoto {
  String id;
  String owner;
  String secret;
  String server;
  String title;
  String farm;

  public FlickrPhoto(String _id, String _owner, String _secret,
      String _server, String _title, String _farm) {
    id = _id;
    owner = _owner;
    secret = _secret;
    server = _server;
    title = _title;
    farm = _farm;
  }

  public String makeURL() {
    return "http://farm" + farm + ".static.flickr.com/" + server + "/"
        + id + "_" + secret + "_m.jpg";
    // http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_[mstzb].jpg
  }
}
//main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ListView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/ListView"></ListView>
</LinearLayout>

Using JSON

   
package app.test;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class Test extends Activity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    String JSONData = ""
        + "{\"results\":{\"aname\":\"value\", \"anumber\":1234, \"aboolean\":false, "
        + "\"anarray\":[{\"arrayelement\":\"Array Element 1\"}, {\"arrayelement\":\"Array Element 2\"}]}}";

    try {
      JSONObject overallJSONObject = new JSONObject(JSONData);
      Log.v("SIMPLEJSON", overallJSONObject.toString());

      JSONObject resultsObject = overallJSONObject
          .getJSONObject("results");
      Log.v("SIMPLEJSON", resultsObject.toString());

      String aname = resultsObject.getString("aname");
      Log.v("SIMPLEJSON", aname);

      int anumber = resultsObject.getInt("anumber");
      Log.v("SIMPLEJSON", "" + anumber);

      boolean aboolean = resultsObject.getBoolean("aboolean");
      Log.v("SIMPLEJSON", "" + aboolean);

      JSONArray anarray = resultsObject.getJSONArray("anarray");
      for (int i = 0; i < anarray.length(); i++) {
        JSONObject arrayElementObject = anarray.getJSONObject(i);
        String arrayelement = arrayElementObject
            .getString("arrayelement");
        Log.v("SIMPLEJSON", arrayelement);
      }
    } catch (JSONException e) {
      e.printStackTrace();
    }
  }
}
Json Client
//package com.mediaportal.ampdroid.api;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;

import android.util.Log;

public class JsonClient {
   public static int DEFAULT_TIMEOUT = 5000;
   
   public enum RequestMethod {
      GET, POST
   }

   private ArrayList<NameValuePair> headers;

   private String url;

   private String mUser;
   private String mPass;
   private boolean mUseAuth;

   private int responseCode;
   private String message;

   private String response;

   public String getResponse() {
      return response;
   }

   public String getErrorMessage() {
      return message;
   }

   public int getResponseCode() {
      return responseCode;
   }

   public JsonClient(String url, String _user, String _pass, boolean _useAuth) {
      this.url = url;
      mUser = _user;
      mPass = _pass;
      mUseAuth = _useAuth;
      headers = new ArrayList<NameValuePair>();
   }

//   public JsonClient(String url) {
//      this(url, null, null, false);
//   }

   public void AddHeader(String name, String value) {
      headers.add(new BasicNameValuePair(name, value));
   }

   public String Execute(String methodName) {
      return Execute(methodName, DEFAULT_TIMEOUT, RequestMethod.GET);
   }
   
   public String Execute(String methodName, int _timeout) {
      return Execute(methodName, _timeout, RequestMethod.GET);
   }
   
   public String Execute(String methodName, int _timeout, NameValuePair... _params) {
      return Execute(methodName, _timeout, RequestMethod.GET, _params);
   }

   public String Execute(String methodName, NameValuePair... _params) {
      return Execute(methodName, RequestMethod.GET, _params);
   }
   
   public String Execute(String methodName, RequestMethod methodType, NameValuePair... _params) {
      try {
         return DoExecute(methodName, DEFAULT_TIMEOUT, methodType, _params);
      } catch (Exception e) {
       
         return null;
      }
   }
   
   public String Execute(String methodName, int _timeout, RequestMethod methodType, NameValuePair... _params) {
      try {
         return DoExecute(methodName, _timeout, methodType, _params);
      } catch (Exception e) {
      
         return null;
      }
   }

   private String DoExecute(String methodName, int _timeout, RequestMethod methodType, NameValuePair... _params)
         throws Exception {
      switch (methodType) {
      case GET: {
         // add parameters
         String combinedParams = "";
         if (_params.length > 0) {
            combinedParams += "?";
            for (NameValuePair p : _params) {
               String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue(), "UTF-8");
               if (combinedParams.length() > 1) {
                  combinedParams += "&" + paramString;
               } else {
                  combinedParams += paramString;
               }
            }
         }

         HttpGet request = new HttpGet(url + "/" + methodName + combinedParams);

         // add headers
         for (NameValuePair h : headers) {
            request.addHeader(h.getName(), h.getValue());
         }

         return executeRequest(request, _timeout, url);
      }
      case POST: {
         HttpPost request = new HttpPost(url + "/" + methodName);

         // add headers
         for (NameValuePair h : headers) {
            request.addHeader(h.getName(), h.getValue());
         }

         if (_params.length > 0) {
            List<NameValuePair> paramList = new ArrayList<NameValuePair>();
            for (NameValuePair p : _params) {
               paramList.add(p);
            }
            request.setEntity(new UrlEncodedFormEntity(paramList, HTTP.UTF_8));
         }

         return executeRequest(request, _timeout, url);
      }
      default:
         return null;
      }
   }

   private String executeRequest(HttpUriRequest request, int _timeout, String url) {
      HttpParams httpParameters = new BasicHttpParams();
      HttpConnectionParams.setConnectionTimeout(httpParameters, _timeout);
      HttpConnectionParams.setSoTimeout(httpParameters, _timeout);
      HttpConnectionParams.setTcpNoDelay(httpParameters, true);

      DefaultHttpClient client = new DefaultHttpClient(httpParameters);
      request.setHeader("User-Agent", "USER_AGENT");

      if (mUseAuth) {
         CredentialsProvider credProvider = new BasicCredentialsProvider();
         credProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
               new UsernamePasswordCredentials(mUser, mPass));
         client.setCredentialsProvider(credProvider);
      }

      HttpResponse httpResponse;

      try {
         httpResponse = client.execute(request);
         responseCode = httpResponse.getStatusLine().getStatusCode();
         message = httpResponse.getStatusLine().getReasonPhrase();

         HttpEntity entity = httpResponse.getEntity();

         if (entity != null) {

            InputStream instream = entity.getContent();
            response = convertStreamToString(instream);

            // Closing the input stream will trigger connection release
            instream.close();

            return response;
         }

      } catch (ClientProtocolException e) {
         client.getConnectionManager().shutdown();
         e.printStackTrace();
      } catch (IOException e) {
         client.getConnectionManager().shutdown();
         e.printStackTrace();
      }
      return null;
   }

   private static String convertStreamToString(InputStream is) {

      BufferedReader reader = new BufferedReader(new InputStreamReader(is));
      StringBuilder sb = new StringBuilder();

      String line = null;
      try {
         while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
         }
      } catch (IOException e) {
         e.printStackTrace();
      } finally {
         try {
            is.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
      return sb.toString();
   }
}

Get List From Json Object

   
//package com.xiledsystems.AlternateJavaBridgelib;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * 
 *  This was mostly copied from com.google.devtools.simple.runtime.components.util.JsonUtil. It has been modified to not
 *  use the FString, or Yaillist classes (so Kawa library not needed)
 *  
 * - Ryan Bis - www.xiledsystems.com
 *
 */

 class JsonUtil2 {

  /**
     * Prevent instantiation.
     */
    private JsonUtil2() {
    }

    /**
     * Returns a list of String objects from a JSONArray. This
     * does not do any kind of recursive unpacking of the array.
     * Thus, if the array includes other JSON arrays or JSON objects
     * their string representation will be a single item in the
     * returned list.
     *
     * @param jArray The JSONArray to convert.
     * @return A List of the String representation of each item in
     * the JSON array.
     * @throws JSONException if an element of jArray cannot be
     * converted to a String.
     */
    public static List<String> getStringListFromJsonArray(JSONArray jArray) throws JSONException {
      List<String> returnList = new ArrayList<String>();
      for (int i = 0; i < jArray.length(); i++) {
        String val = jArray.getString(i);
        returnList.add(val);
      }
      return returnList;
    }

    /**
     * Returns a Java Object list of a JSONArray with each item in
     * the array converted using convertJsonItem().
     *
     * @param jArray The JSONArray to convert.
     * @return A List of Strings and more Object lists.
     * @throws JSONException if an element in jArray cannot be
     * converted properly.
     */
    public static List<Object> getListFromJsonArray(JSONArray jArray) throws JSONException {
      List<Object> returnList = new ArrayList<Object>();
      for (int i = 0; i < jArray.length(); i++) {
        returnList.add(convertJsonItem(jArray.get(i)));
      }
      return returnList;
    }

    /**
     * Returns a list containing one two item list per key in jObject.
     * Each two item list has the key String as its first element and
     * the result of calling convertJsonItem() on its value as the
     * second element. The sub-lists in the returned list will appear
     * in alphabetical order by key.
     *
     * @param jObject The JSONObject to convert.
     * @return A list of two item lists: [String key, Object value].
     * @throws JSONException if an element in jObject cannot be
     * converted properly.
     */
    @SuppressWarnings("unchecked")
  public static List<Object> getListFromJsonObject(JSONObject jObject) throws JSONException {
      List<Object> returnList = new ArrayList<Object>();
      Iterator<String> keys = jObject.keys();

      List<String> keysList = new ArrayList<String>();
      while (keys.hasNext()) {
        keysList.add(keys.next());
      }
      Collections.sort(keysList);

      for (String key : keysList) {
        List<Object> nestedList = new ArrayList<Object>();
        nestedList.add(key);
        nestedList.add(convertJsonItem(jObject.get(key)));
        returnList.add(nestedList);
      }

      return returnList;
    }

    /**
     * Returns a Java object representation of objects that are
     * encountered inside of JSON created using the org.json package.
     * JSON arrays and objects are transformed into their list
     * representations using getListFromJsonArray and
     * getListFromJsonObject respectively.
     *
     * Java Boolean values and the Strings "true" and "false" (case
     * insensitive) are inserted as Booleans. Java Numbers are
     * inserted without modification and all other values are inserted
     * as their toString(). value.
     *
     * @param o An item in a JSON array or JSON object to convert.
     * @return A Java Object representing o or the String "null"
     * if o is null.
     * @throws JSONException if o fails to parse.
     */
    public static Object convertJsonItem(Object o) throws JSONException {
      if (o == null) {
        return "null";
      }

      if (o instanceof JSONObject) {
        return getListFromJsonObject((JSONObject) o);
      }

      if (o instanceof JSONArray) {
        return getListFromJsonArray((JSONArray) o);
      }

      if (o.equals(Boolean.FALSE) || (o instanceof String &&
          ((String) o).equalsIgnoreCase("false"))) {
        return false;
      }

      if (o.equals(Boolean.TRUE) || (o instanceof String && ((String) o).equalsIgnoreCase("true"))) {
        return true;
      }

      if (o instanceof Number) {
        return o;
      }

      return o.toString();
    }

    public static String getJsonRepresentation(Object value) throws JSONException {
      if (value == null || value.equals(null)) {
        return "null";
      }
      /*
       * This has been commented out to prevent the need for the Kawa library. Do NOT use Fstring
       * or YailList in any of your data, otherwise this conversion won't work.
       * 
      if (value instanceof FString) {
        return JSONObject.quote(value.toString());
      }
      if (value instanceof YailList) {
        return ((YailList) value).toJSONString();
      }
      */
      
      if (value instanceof Number) {
        return JSONObject.numberToString((Number) value);
      }
      if (value instanceof Boolean) {
        return value.toString();
      }
      if (value.getClass().isArray()) {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        String separator = "";
        for (Object o: (Object[]) value) {
          sb.append(separator).append(getJsonRepresentation(o));
          separator = ",";
        }
        sb.append("]");
        return sb.toString();
      }
      if (value instanceof String) {
        return value.toString();
      }
      return JSONObject.quote(value.toString());
    }

    public static Object getObjectFromJson(String jsonString) throws JSONException {
      final Object value = (new JSONTokener(jsonString)).nextValue();
      // Note that the JSONTokener may return a value equals() to null.
      if (value == null || value.equals(null)) {
        return null;
      } else if ((value instanceof String) ||
                 (value instanceof Number) ||
                 (value instanceof Boolean)) {
        return value;
      } else if (value instanceof JSONArray) {
        return getListFromJsonArray((JSONArray)value);
      } else if (value instanceof JSONObject) {
        return getListFromJsonObject((JSONObject)value);
      }
      throw new JSONException("Invalid JSON string.");
    }
}
  

Create JSONObject

   


import java.io.File;

import org.json.JSONObject;
import org.json.JSONArray;

import android.os.Environment;
import android.util.Log;

class FileUtil {

  public static JSONObject GetDirJSON(File dir)
  {
      JSONObject jsonObj=new JSONObject();
      try
      {
      jsonObj.put("name", dir.getName());
      jsonObj.put("directory", dir.isDirectory());
      jsonObj.put("url", dir.getAbsolutePath());
    if(dir.equals(Environment.getExternalStorageDirectory()))
    {
      jsonObj.put("root", true);
    }
    else
    {
      jsonObj.put("root", false);
      jsonObj.put("parent", dir.getParent());
    }
    
    if(dir.isDirectory())
    {
      File[] subFs=dir.listFiles();
      JSONArray array=new JSONArray();
      for(int i=0;i<subFs.length;i++)
        array.put(subFs[i].getName());
      
    
      jsonObj.put("sub", array);
    }
    
      }catch(Exception e)
      {
        Log.d("Exec", e.getMessage());
      }
      Log.d("FileUtil",jsonObj.toString());
    return jsonObj;
  }
}

JSON: Get node value,

   

//package com.omar.labs.tamtamy.JSON;

import java.net.URLEncoder;
import java.util.ArrayList;

public class JSONUtility {

  public static String getNodeValue(String json, String propName){
    String tmp = null;
    int match = json.indexOf(propName+":");
    if(match!=-1){
    int start = match + (propName+":").length();
    int stop = json.indexOf(",", start);    
    try{
      if(stop>0 && stop-start>1 && json.charAt(start)=='"')        
        tmp = json.substring(start+1, stop-1);
      else if(stop>0)
        tmp = json.substring(start, stop);  
      else
        tmp = json.substring(start+1);  
    }catch (Exception ex){

    }    
    if(tmp.indexOf("\"}")!=-1)
      tmp = tmp.substring(0, tmp.length()-2);
    }
    return tmp; 
  }
  
  public static ArrayList getNodesValue(String json){
    
    if(json.startsWith("\""))
      json = json.substring(1);
    if(json.endsWith("\"")) 
      json = json.substring(0, json.length()-1); 
    
    if(json.startsWith("["))
      json = json.substring(1);
    if(json.endsWith("]")) 
      json = json.substring(0, json.length()-1); 
      
    String[] tmp = json.split(",");
    ArrayList<String> tmpArr = new ArrayList<String>();
    for(int t=0; t<tmp.length; t++){
      String element = tmp[t];
      if(element.startsWith("\""))
          element = element.substring(1);
      if(element.endsWith("\"")) 
        element = element.substring(0, element.length()-1);        
      tmpArr.add(element);
    }
        
    return tmpArr;
  }
  
  /*
  public static String getNodeValueWithList(String json, String propName){    
    String tmp = null;    
    int start = json.indexOf(propName+":") + (propName+":").length();
    int stop = json.indexOf("]", start);    
    try{
      if(stop>0)
        tmp = json.substring(start, stop);
      else
      tmp = json.substring(start);  
    }catch (Exception ex){
        
    }    
    if(tmp.indexOf("\"")!=-1)
      tmp = tmp.substring(1, tmp.length()-1);    
    return tmp; 
  }
  */
  
  public static ArrayList<String> getNodeValueWithList(String json, String propName){    
    ArrayList<String> tmpA = new ArrayList<String>();
    String tmp = null;    
    int start = json.indexOf(propName+":") + (propName+":").length();
    int stop = json.indexOf("]", start);
    int stop1 = json.lastIndexOf("]");
    try{
      if (stop>0 && stop == stop1){
      tmp = json.substring(start+1, stop);
      }else if(stop1>0){
      tmp = json.substring(start+1, stop1);   
      }else{  
      tmp = json.substring(start, json.length()-1);
      }  
    }catch (Exception ex){
        ex.printStackTrace();
    }    
    //if(tmp.indexOf("\"")!=-1)
    //  tmp = tmp.substring(1, tmp.length());
    
    String[] items = null;
    if(tmp.indexOf("},{")==-1 && !propName.equals("\"list\""))
      items = tmp.split(",");
    else
      items = tmp.split("\\},\\{");
    for(int i=0; i<items.length; i++){
      tmpA.add(items[i]);
    }        
    return tmpA; 
  }  
}

Data type conversion for JSON

   
//package org.beryl.util;

import org.json.JSONException;
import org.json.JSONObject;

 class TryParse {

  public static int toInt(String value, int defaultValue) {
    int result;

    try {
      result = Integer.parseInt(value);
    } catch(NumberFormatException e) { result = defaultValue; }

    return result;
  }

  public static String toString(JSONObject json, String name, String defaultValue) {
    String result;
    try {
      result = json.getString(name);
    } catch(JSONException e) { result = defaultValue; }

    return result;
  }

  public static int toInt(JSONObject json, String name, int defaultValue) {
    int result;
    try {
      result = json.getInt(name);
    } catch(JSONException e) { result = defaultValue; }

    return result;
  }

  public static boolean toBoolean(JSONObject json, String name, boolean defaultValue) {
    boolean result;
    try {
      result = json.getBoolean(name);
    } catch(JSONException e) { result = defaultValue; }

    return result;
  }
}
Object to JSON
//package org.comet4j.core.util;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * ????????json???,???????
 * @author xiaojinghai
 * @date 2011-7-18
 */

public class JSONUtil {

  public static String object2json(Object obj) {
    StringBuilder json = new StringBuilder();
    if (obj == null) {
      json.append("\"\"");
    } else if (obj instanceof String || obj instanceof Integer || obj instanceof Float || obj instanceof Boolean
        || obj instanceof Short || obj instanceof Double || obj instanceof Long || obj instanceof BigDecimal
        || obj instanceof BigInteger || obj instanceof Byte) {
      json.append("\"").append(string2json(obj.toString())).append("\"");
    } else if (obj instanceof Object[]) {
      json.append(array2json((Object[]) obj));
    } else if (obj instanceof List) {
      json.append(list2json((List<?>) obj));
    } else if (obj instanceof Map) {
      json.append(map2json((Map<?, ?>) obj));
    } else if (obj instanceof Set) {
      json.append(set2json((Set<?>) obj));
    } 
    return json.toString();
  }

  public static String list2json(List<?> list) {
    StringBuilder json = new StringBuilder();
    json.append("[");
    if (list != null && list.size() > 0) {
      for (Object obj : list) {
        json.append(object2json(obj));
        json.append(",");
      }
      json.setCharAt(json.length() - 1, ']');
    } else {
      json.append("]");
    }
    return json.toString();
  }

  public static String array2json(Object[] array) {
    StringBuilder json = new StringBuilder();
    json.append("[");
    if (array != null && array.length > 0) {
      for (Object obj : array) {
        json.append(object2json(obj));
        json.append(",");
      }
      json.setCharAt(json.length() - 1, ']');
    } else {
      json.append("]");
    }
    return json.toString();
  }

  public static String map2json(Map<?, ?> map) {
    StringBuilder json = new StringBuilder();
    json.append("{");
    if (map != null && map.size() > 0) {
      for (Object key : map.keySet()) {
        json.append(object2json(key));
        json.append(":");
        json.append(object2json(map.get(key)));
        json.append(",");
      }
      json.setCharAt(json.length() - 1, '}');
    } else {
      json.append("}");
    }
    return json.toString();
  }

  public static String set2json(Set<?> set) {
    StringBuilder json = new StringBuilder();
    json.append("[");
    if (set != null && set.size() > 0) {
      for (Object obj : set) {
        json.append(object2json(obj));
        json.append(",");
      }
      json.setCharAt(json.length() - 1, ']');
    } else {
      json.append("]");
    }
    return json.toString();
  }

  public static String string2json(String s) {
    if (s == null) return "";
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < s.length(); i++) {
      char ch = s.charAt(i);
      switch (ch) {
        case '"':
          sb.append("\\\"");
          break;
        case '\\':
          sb.append("\\\\");
          break;
        case '\b':
          sb.append("\\b");
          break;
        case '\f':
          sb.append("\\f");
          break;
        case '\n':
          sb.append("\\n");
          break;
        case '\r':
          sb.append("\\r");
          break;
        case '\t':
          sb.append("\\t");
          break;
        case '/':
          sb.append("\\/");
          break;
        default:
          if (ch >= '\u0000' && ch <= '\u001F') {
            String ss = Integer.toHexString(ch);
            sb.append("\\u");
            for (int k = 0; k < 4 - ss.length(); k++) {
              sb.append('0');
            }
            sb.append(ss.toUpperCase());
          } else {
            sb.append(ch);
          }
      }
    }
    return sb.toString();
  }
}
Wikidictionary
package com.example.android.simplewiktionary;

import com.example.android.simplewiktionary.SimpleWikiHelper.ApiException;
import com.example.android.simplewiktionary.SimpleWikiHelper.ParseException;

import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.IBinder;
import android.text.format.Time;
import android.util.Log;
import android.widget.RemoteViews;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;


 class SimpleWikiHelper {
    private static final String TAG = "SimpleWikiHelper";


    public static final String WORD_OF_DAY_REGEX =
            "(?s)\\{\\{wotd\\|(.+?)\\|(.+?)\\|([^#\\|]+).*?\\}\\}";


    private static final String WIKTIONARY_PAGE =
            "http://en.wiktionary.org/w/api.php?action=query&prop=revisions&titles=%s&" +
            "rvprop=content&format=json%s";

    /**
     * Partial URL to append to {@link #WIKTIONARY_PAGE} when you want to expand
     * any templates found on the requested page. This is useful when browsing
     * full entries, but may use more network bandwidth.
     */
    private static final String WIKTIONARY_EXPAND_TEMPLATES =
            "&rvexpandtemplates=true";

    /**
     * {@link StatusLine} HTTP status code when no server error has occurred.
     */
    private static final int HTTP_STATUS_OK = 200;

    /**
     * Shared buffer used by {@link #getUrlContent(String)} when reading results
     * from an API request.
     */
    private static byte[] sBuffer = new byte[512];

    /**
     * User-agent string to use when making requests. Should be filled using
     * {@link #prepareUserAgent(Context)} before making any other calls.
     */
    private static String sUserAgent = null;

    /**
     * Thrown when there were problems contacting the remote API server, either
     * because of a network error, or the server returned a bad status code.
     */
    public static class ApiException extends Exception {
        public ApiException(String detailMessage, Throwable throwable) {
            super(detailMessage, throwable);
        }

        public ApiException(String detailMessage) {
            super(detailMessage);
        }
    }

    public static class ParseException extends Exception {
        public ParseException(String detailMessage, Throwable throwable) {
            super(detailMessage, throwable);
        }
    }


    public static void prepareUserAgent(Context context) {
        try {
            // Read package name and version number from manifest
            PackageManager manager = context.getPackageManager();
            PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
            sUserAgent = String.format(context.getString(R.string.template_user_agent),
                    info.packageName, info.versionName);

        } catch(NameNotFoundException e) {
            Log.e(TAG, "Couldn't find package information in PackageManager", e);
        }
    }

    public static String getPageContent(String title, boolean expandTemplates)
            throws ApiException, ParseException {
        // Encode page title and expand templates if requested
        String encodedTitle = Uri.encode(title);
        String expandClause = expandTemplates ? WIKTIONARY_EXPAND_TEMPLATES : "";

        // Query the API for content
        String content = getUrlContent(String.format(WIKTIONARY_PAGE,
                encodedTitle, expandClause));
        try {
            // Drill into the JSON response to find the content body
            JSONObject response = new JSONObject(content);
            JSONObject query = response.getJSONObject("query");
            JSONObject pages = query.getJSONObject("pages");
            JSONObject page = pages.getJSONObject((String) pages.keys().next());
            JSONArray revisions = page.getJSONArray("revisions");
            JSONObject revision = revisions.getJSONObject(0);
            return revision.getString("*");
        } catch (JSONException e) {
            throw new ParseException("Problem parsing API response", e);
        }
    }


    protected static synchronized String getUrlContent(String url) throws ApiException {
        if (sUserAgent == null) {
            throw new ApiException("User-Agent string must be prepared");
        }

        // Create client and set our specific user-agent string
        HttpClient client = new DefaultHttpClient();
        HttpGet request = new HttpGet(url);
        request.setHeader("User-Agent", sUserAgent);

        try {
            HttpResponse response = client.execute(request);

            // Check if server response is valid
            StatusLine status = response.getStatusLine();
            if (status.getStatusCode() != HTTP_STATUS_OK) {
                throw new ApiException("Invalid response from server: " +
                        status.toString());
            }

            // Pull content stream from response
            HttpEntity entity = response.getEntity();
            InputStream inputStream = entity.getContent();

            ByteArrayOutputStream content = new ByteArrayOutputStream();

            // Read response into a buffered stream
            int readBytes = 0;
            while ((readBytes = inputStream.read(sBuffer)) != -1) {
                content.write(sBuffer, 0, readBytes);
            }

            // Return result from buffered stream
            return new String(content.toByteArray());
        } catch (IOException e) {
            throw new ApiException("Problem communicating with API", e);
        }
    }
}

/**
 * Define a simple widget that shows the Wiktionary "Word of the day." To build
 * an update we spawn a background {@link Service} to perform the API queries.
 */
public class WordWidget extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
            int[] appWidgetIds) {
        // To prevent any ANR timeouts, we perform the update in a service
        context.startService(new Intent(context, UpdateService.class));
    }

    public static class UpdateService extends Service {
        @Override
        public void onStart(Intent intent, int startId) {
            // Build the widget update for today
            RemoteViews updateViews = buildUpdate(this);

            // Push update for this widget to the home screen
            ComponentName thisWidget = new ComponentName(this, WordWidget.class);
            AppWidgetManager manager = AppWidgetManager.getInstance(this);
            manager.updateAppWidget(thisWidget, updateViews);
        }

        /**
         * Build a widget update to show the current Wiktionary
         * "Word of the day." Will block until the online API returns.
         */
        public RemoteViews buildUpdate(Context context) {
            // Pick out month names from resources
            Resources res = context.getResources();
            String[] monthNames = res.getStringArray(R.array.month_names);

            // Find current month and day
            Time today = new Time();
            today.setToNow();

            // Build today's page title, like "Wiktionary:Word of the day/March 21"
            String pageName = res.getString(R.string.template_wotd_title,
                    monthNames[today.month], today.monthDay);
            RemoteViews updateViews = null;
            String pageContent = "";

            try {
                // Try querying the Wiktionary API for today's word
                SimpleWikiHelper.prepareUserAgent(context);
                pageContent = SimpleWikiHelper.getPageContent(pageName, false);
            } catch (ApiException e) {
                Log.e("WordWidget", "Couldn't contact API", e);
            } catch (ParseException e) {
                Log.e("WordWidget", "Couldn't parse API response", e);
            }

            // Use a regular expression to parse out the word and its definition
            Pattern pattern = Pattern.compile(SimpleWikiHelper.WORD_OF_DAY_REGEX);
            Matcher matcher = pattern.matcher(pageContent);
            if (matcher.find()) {
                // Build an update that holds the updated widget contents
                updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);

                String wordTitle = matcher.group(1);
                updateViews.setTextViewText(R.id.word_title, wordTitle);
                updateViews.setTextViewText(R.id.word_type, matcher.group(2));
                updateViews.setTextViewText(R.id.definition, matcher.group(3).trim());

                // When user clicks on widget, launch to Wiktionary definition page
                String definePage = res.getString(R.string.template_define_url,
                        Uri.encode(wordTitle));
                Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage));
                PendingIntent pendingIntent = PendingIntent.getActivity(context,
                        0 /* no requestCode */, defineIntent, 0 /* no flags */);
                updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent);

            } else {
                // Didn't find word of day, so show error message
                updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_message);
                CharSequence errorMessage = context.getText(R.string.widget_error);
                updateViews.setTextViewText(R.id.message, errorMessage);
            }
            return updateViews;
        }

        @Override
        public IBinder onBind(Intent intent) {
            // We don't need to bind to this service
            return null;
        }
    }
}
//
//res\layout\widget_message.xml
<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    style="@style/WidgetBackground">

    <TextView
        android:id="@+id/message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dip"
        android:padding="10dip"
        android:gravity="center"
        android:text="@string/widget_loading"
        style="@style/Text.Loading" />

</LinearLayout>



//res\layout\widget_word.xml
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusable="true"
    style="@style/WidgetBackground">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:src="@drawable/star_logo" />

    <TextView
        android:id="@+id/word_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="14dip"
        android:layout_marginBottom="1dip"
        android:includeFontPadding="false"
        android:singleLine="true"
        android:ellipsize="end"
        style="@style/Text.WordTitle" />

    <TextView
        android:id="@+id/word_type"
        android:layout_width="0dip"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/word_title"
        android:layout_toLeftOf="@id/icon"
        android:layout_alignBaseline="@id/word_title"
        android:paddingLeft="4dip"
        android:includeFontPadding="false"
        android:singleLine="true"
        android:ellipsize="end"
        style="@style/Text.WordType" />

    <TextView
        android:id="@+id/bullet"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/word_title"
        android:paddingRight="4dip"
        android:includeFontPadding="false"
        android:singleLine="true"
        style="@style/BulletPoint" />

    <TextView
        android:id="@+id/definition"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/word_title"
        android:layout_toRightOf="@id/bullet"
        android:paddingRight="5dip"
        android:paddingBottom="4dip"
        android:includeFontPadding="false"
        android:lineSpacingMultiplier="0.9"
        android:maxLines="4"
        android:fadingEdge="vertical"
        style="@style/Text.Definition" />

</RelativeLayout>



//
//res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>


<resources>
    <string name="app_name">Wiktionary simple example</string>

    <string name="template_user_agent" translatable="false">"%1$s/%2$s (Linux; Android)"</string>
    <string name="template_wotd_title">"Wiktionary:Word of the day/%1$s %2$s"</string>
    <string name="template_define_url" translatable="false">"http://en.wiktionary.org/wiki/%s"</string>

    <string name="widget_name">Wiktionary simple</string>

    <string name="widget_loading">Loading word\nof day\u2026</string>
    <string name="widget_error">No word of\nday found</string>

    <string-array name="month_names">
        <item>January</item>
        <item>February</item>
        <item>March</item>
        <item>April</item>
        <item>May</item>
        <item>June</item>
        <item>July</item>
        <item>August</item>
        <item>September</item>
        <item>October</item>
        <item>November</item>
        <item>December</item>
    </string-array>

</resources>



//res\values\styles.xml
<?xml version="1.0" encoding="utf-8"?>


<resources>

    <style name="WidgetBackground">
        <item name="android:background">@drawable/widget_bg</item>
    </style>

    <style name="BulletPoint">
        <item name="android:textSize">13sp</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

    <style name="Text" />

    <style name="Text.Loading">
        <item name="android:textSize">14sp</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

    <style name="Text.WordTitle">
        <item name="android:textSize">16sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

    <style name="Text.WordType">
        <item name="android:textSize">14sp</item>
        <item name="android:textStyle">italic</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

    <style name="Text.Definition">
        <item name="android:textSize">13sp</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

</resources>



//
//res\xml\widget_word.xml
<?xml version="1.0" encoding="utf-8"?>


<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="146dip"
    android:minHeight="72dip"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/widget_message" />
Browse through Wiktionary content
package com.example.android.wiktionary;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.net.Uri;
import android.text.TextUtils;
import android.webkit.WebView;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Extended version of {@link SimpleWikiHelper}. This version adds methods to
 * pick a random word, and to format generic wiki-style text into HTML.
 */
public class ExtendedWikiHelper extends SimpleWikiHelper {
    /**
     * HTML style sheet to include with any {@link #formatWikiText(String)} HTML
     * results. It formats nicely for a mobile screen, and hides some content
     * boxes to keep things tidy.
     */
    private static final String STYLE_SHEET = "<style>h2 {font-size:1.2em;font-weight:normal;} " +
            "a {color:#6688cc;} ol {padding-left:1.5em;} blockquote {margin-left:0em;} " +
            ".interProject, .noprint {display:none;} " +
            "li, blockquote {margin-top:0.5em;margin-bottom:0.5em;}</style>";

    /**
     * Pattern of section titles we're interested in showing. This trims out
     * extra sections that can clutter things up on a mobile screen.
     */
    private static final Pattern sValidSections =
        Pattern.compile("(verb|noun|adjective|pronoun|interjection)", Pattern.CASE_INSENSITIVE);

    /**
     * Pattern that can be used to split a returned wiki page into its various
     * sections. Doesn't treat children sections differently.
     */
    private static final Pattern sSectionSplit =
        Pattern.compile("^=+(.+?)=+.+?(?=^=)", Pattern.MULTILINE | Pattern.DOTALL);

    /**
     * When picking random words in {@link #getRandomWord()}, we sometimes
     * encounter special articles or templates. This pattern ignores any words
     * like those, usually because they have ":" or other punctuation.
     */
    private static final Pattern sInvalidWord = Pattern.compile("[^A-Za-z0-9 ]");

    /**
     * {@link Uri} authority to use when creating internal links.
     */
    public static final String WIKI_AUTHORITY = "wiktionary";

    /**
     * {@link Uri} host to use when creating internal links.
     */
    public static final String WIKI_LOOKUP_HOST = "lookup";

    /**
     * Mime-type to use when showing parsed results in a {@link WebView}.
     */
    public static final String MIME_TYPE = "text/html";

    /**
     * Encoding to use when showing parsed results in a {@link WebView}.
     */
    public static final String ENCODING = "utf-8";

    /**
     * {@link Uri} to use when requesting a random page.
     */
    private static final String WIKTIONARY_RANDOM =
        "http://en.wiktionary.org/w/api.php?action=query&list=random&format=json";

    /**
     * Fake section to insert at the bottom of a wiki response before parsing.
     * This ensures that {@link #sSectionSplit} will always catch the last
     * section, as it uses section headers in its searching.
     */
    private static final String STUB_SECTION = "\n=Stub section=";

    /**
     * Number of times to try finding a random word in {@link #getRandomWord()}.
     * These failures are usually when the found word fails the
     * {@link #sInvalidWord} test, or when a network error happens.
     */
    private static final int RANDOM_TRIES = 3;

    /**
     * Internal class to hold a wiki formatting rule. It's mostly a wrapper to
     * simplify {@link Matcher#replaceAll(String)}.
     */
    private static class FormatRule {
        private Pattern mPattern;
        private String mReplaceWith;

        /**
         * Create a wiki formatting rule.
         *
         * @param pattern Search string to be compiled into a {@link Pattern}.
         * @param replaceWith String to replace any found occurances with. This
         *            string can also include back-references into the given
         *            pattern.
         * @param flags Any flags to compile the {@link Pattern} with.
         */
        public FormatRule(String pattern, String replaceWith, int flags) {
            mPattern = Pattern.compile(pattern, flags);
            mReplaceWith = replaceWith;
        }

        /**
         * Create a wiki formatting rule.
         *
         * @param pattern Search string to be compiled into a {@link Pattern}.
         * @param replaceWith String to replace any found occurances with. This
         *            string can also include back-references into the given
         *            pattern.
         */
        public FormatRule(String pattern, String replaceWith) {
            this(pattern, replaceWith, 0);
        }

        /**
         * Apply this formatting rule to the given input string, and return the
         * resulting new string.
         */
        public String apply(String input) {
            Matcher m = mPattern.matcher(input);
            return m.replaceAll(mReplaceWith);
        }

    }

    /**
     * List of internal formatting rules to apply when parsing wiki text. These
     * include indenting various bullets, apply italic and bold styles, and
     * adding internal linking.
     */
    private static final List<FormatRule> sFormatRules = new ArrayList<FormatRule>();

    static {
        // Format header blocks and wrap outside content in ordered list
        sFormatRules.add(new FormatRule("^=+(.+?)=+", "</ol><h2>$1</h2><ol>",
                Pattern.MULTILINE));

        // Indent quoted blocks, handle ordered and bullet lists
        sFormatRules.add(new FormatRule("^#+\\*?:(.+?)$", "<blockquote>$1</blockquote>",
                Pattern.MULTILINE));
        sFormatRules.add(new FormatRule("^#+:?\\*(.+?)$", "<ul><li>$1</li></ul>",
                Pattern.MULTILINE));
        sFormatRules.add(new FormatRule("^#+(.+?)$", "<li>$1</li>",
                Pattern.MULTILINE));

        // Add internal links
        sFormatRules.add(new FormatRule("\\[\\[([^:\\|\\]]+)\\]\\]",
                String.format("<a href=\"%s://%s/$1\">$1</a>", WIKI_AUTHORITY, WIKI_LOOKUP_HOST)));
        sFormatRules.add(new FormatRule("\\[\\[([^:\\|\\]]+)\\|([^\\]]+)\\]\\]",
                String.format("<a href=\"%s://%s/$1\">$2</a>", WIKI_AUTHORITY, WIKI_LOOKUP_HOST)));

        // Add bold and italic formatting
        sFormatRules.add(new FormatRule("'''(.+?)'''", "<b>$1</b>"));
        sFormatRules.add(new FormatRule("([^'])''([^'].*?[^'])''([^'])", "$1<i>$2</i>$3"));

        // Remove odd category links and convert remaining links into flat text
        sFormatRules.add(new FormatRule("(\\{+.+?\\}+|\\[\\[[^:]+:[^\\\\|\\]]+\\]\\]|" +
                "\\[http.+?\\]|\\[\\[Category:.+?\\]\\])", "", Pattern.MULTILINE | Pattern.DOTALL));
        sFormatRules.add(new FormatRule("\\[\\[([^\\|\\]]+\\|)?(.+?)\\]\\]", "$2",
                Pattern.MULTILINE));

    }

 
    public static String getRandomWord() throws ApiException, ParseException {
        // Keep trying a few times until we find a valid word
        int tries = 0;
        while (tries++ < RANDOM_TRIES) {
            // Query the API for a random word
            String content = getUrlContent(WIKTIONARY_RANDOM);
            try {
                // Drill into the JSON response to find the returned word
                JSONObject response = new JSONObject(content);
                JSONObject query = response.getJSONObject("query");
                JSONArray random = query.getJSONArray("random");
                JSONObject word = random.getJSONObject(0);
                String foundWord = word.getString("title");

                // If we found an actual word, and it wasn't rejected by our invalid
                // filter, then accept and return it.
                if (foundWord != null &&
                        !sInvalidWord.matcher(foundWord).find()) {
                    return foundWord;
                }
            } catch (JSONException e) {
                throw new ParseException("Problem parsing API response", e);
            }
        }

        // No valid word found in number of tries, so return null
        return null;
    }

    /**
     * Format the given wiki-style text into formatted HTML content. This will
     * create headers, lists, internal links, and style formatting for any wiki
     * markup found.
     *
     * @param wikiText The raw text to format, with wiki-markup included.
     * @return HTML formatted content, ready for display in {@link WebView}.
     */
    public static String formatWikiText(String wikiText) {
        if (wikiText == null) {
            return null;
        }

        // Insert a fake last section into the document so our section splitter
        // can correctly catch the last section.
        wikiText = wikiText.concat(STUB_SECTION);

        // Read through all sections, keeping only those matching our filter,
        // and only including the first entry for each title.
        HashSet<String> foundSections = new HashSet<String>();
        StringBuilder builder = new StringBuilder();

        Matcher sectionMatcher = sSectionSplit.matcher(wikiText);
        while (sectionMatcher.find()) {
            String title = sectionMatcher.group(1);
            if (!foundSections.contains(title) &&
                    sValidSections.matcher(title).matches()) {
                String sectionContent = sectionMatcher.group();
                foundSections.add(title);
                builder.append(sectionContent);
            }
        }

        // Our new wiki text is the selected sections only
        wikiText = builder.toString();

        // Apply all formatting rules, in order, to the wiki text
        for (FormatRule rule : sFormatRules) {
            wikiText = rule.apply(wikiText);
        }

        // Return the resulting HTML with style sheet, if we have content left
        if (!TextUtils.isEmpty(wikiText)) {
            return STYLE_SHEET + wikiText;
        } else {
            return null;
        }
    }

}



//src\com\example\android\wiktionary\LookupActivity.java


package com.example.android.wiktionary;

import com.example.android.wiktionary.SimpleWikiHelper.ApiException;
import com.example.android.wiktionary.SimpleWikiHelper.ParseException;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.SearchManager;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Animation.AnimationListener;
import android.webkit.WebView;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.util.Stack;

/**
 * Activity that lets users browse through Wiktionary content. This is just the
 * user interface, and all API communication and parsing is handled in
 * {@link ExtendedWikiHelper}.
 */
public class LookupActivity extends Activity implements AnimationListener {
    private static final String TAG = "LookupActivity";

    private View mTitleBar;
    private TextView mTitle;
    private ProgressBar mProgress;
    private WebView mWebView;

    private Animation mSlideIn;
    private Animation mSlideOut;

    /**
     * History stack of previous words browsed in this session. This is
     * referenced when the user taps the "back" key, to possibly intercept and
     * show the last-visited entry, instead of closing the activity.
     */
    private Stack<String> mHistory = new Stack<String>();

    private String mEntryTitle;

    /**
     * Keep track of last time user tapped "back" hard key. When pressed more
     * than once within {@link #BACK_THRESHOLD}, we treat let the back key fall
     * through and close the app.
     */
    private long mLastPress = -1;

    private static final long BACK_THRESHOLD = DateUtils.SECOND_IN_MILLIS / 2;

    /**
     * {@inheritDoc}
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.lookup);

        // Load animations used to show/hide progress bar
        mSlideIn = AnimationUtils.loadAnimation(this, R.anim.slide_in);
        mSlideOut = AnimationUtils.loadAnimation(this, R.anim.slide_out);

        // Listen for the "in" animation so we make the progress bar visible
        // only after the sliding has finished.
        mSlideIn.setAnimationListener(this);

        mTitleBar = findViewById(R.id.title_bar);
        mTitle = (TextView) findViewById(R.id.title);
        mProgress = (ProgressBar) findViewById(R.id.progress);
        mWebView = (WebView) findViewById(R.id.webview);

        // Make the view transparent to show background
        mWebView.setBackgroundColor(0);

        // Prepare User-Agent string for wiki actions
        ExtendedWikiHelper.prepareUserAgent(this);

        // Handle incoming intents as possible searches or links
        onNewIntent(getIntent());
    }

    /**
     * Intercept the back-key to try walking backwards along our word history
     * stack. If we don't have any remaining history, the key behaves normally
     * and closes this activity.
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // Handle back key as long we have a history stack
        if (keyCode == KeyEvent.KEYCODE_BACK && !mHistory.empty()) {

            // Compare against last pressed time, and if user hit multiple times
            // in quick succession, we should consider bailing out early.
            long currentPress = SystemClock.uptimeMillis();
            if (currentPress - mLastPress < BACK_THRESHOLD) {
                return super.onKeyDown(keyCode, event);
            }
            mLastPress = currentPress;

            // Pop last entry off stack and start loading
            String lastEntry = mHistory.pop();
            startNavigating(lastEntry, false);

            return true;
        }

        // Otherwise fall through to parent
        return super.onKeyDown(keyCode, event);
    }

    /**
     * Start navigating to the given word, pushing any current word onto the
     * history stack if requested. The navigation happens on a background thread
     * and updates the GUI when finished.
     *
     * @param word The dictionary word to navigate to.
     * @param pushHistory If true, push the current word onto history stack.
     */
    private void startNavigating(String word, boolean pushHistory) {
        // Push any current word onto the history stack
        if (!TextUtils.isEmpty(mEntryTitle) && pushHistory) {
            mHistory.add(mEntryTitle);
        }

        // Start lookup for new word in background
        new LookupTask().execute(word);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.lookup, menu);
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.lookup_search: {
                onSearchRequested();
                return true;
            }
            case R.id.lookup_random: {
                startNavigating(null, true);
                return true;
            }
            case R.id.lookup_about: {
                showAbout();
                return true;
            }
        }
        return false;
    }

    /**
     * Show an about dialog that cites data sources.
     */
    protected void showAbout() {
        // Inflate the about message contents
        View messageView = getLayoutInflater().inflate(R.layout.about, null, false);

        // When linking text, force to always use default color. This works
        // around a pressed color state bug.
        TextView textView = (TextView) messageView.findViewById(R.id.about_credits);
        int defaultColor = textView.getTextColors().getDefaultColor();
        textView.setTextColor(defaultColor);

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setIcon(R.drawable.app_icon);
        builder.setTitle(R.string.app_name);
        builder.setView(messageView);
        builder.create();
        builder.show();
    }

    /**
     * Because we're singleTop, we handle our own new intents. These usually
     * come from the {@link SearchManager} when a search is requested, or from
     * internal links the user clicks on.
     */
    @Override
    public void onNewIntent(Intent intent) {
        final String action = intent.getAction();
        if (Intent.ACTION_SEARCH.equals(action)) {
            // Start query for incoming search request
            String query = intent.getStringExtra(SearchManager.QUERY);
            startNavigating(query, true);

        } else if (Intent.ACTION_VIEW.equals(action)) {
            // Treat as internal link only if valid Uri and host matches
            Uri data = intent.getData();
            if (data != null && ExtendedWikiHelper.WIKI_LOOKUP_HOST
                    .equals(data.getHost())) {
                String query = data.getPathSegments().get(0);
                startNavigating(query, true);
            }

        } else {
            // If not recognized, then start showing random word
            startNavigating(null, true);
        }
    }

    /**
     * Set the title for the current entry.
     */
    protected void setEntryTitle(String entryText) {
        mEntryTitle = entryText;
        mTitle.setText(mEntryTitle);
    }

    /**
     * Set the content for the current entry. This will update our
     * {@link WebView} to show the requested content.
     */
    protected void setEntryContent(String entryContent) {
        mWebView.loadDataWithBaseURL(ExtendedWikiHelper.WIKI_AUTHORITY, entryContent,
                ExtendedWikiHelper.MIME_TYPE, ExtendedWikiHelper.ENCODING, null);
    }

    /**
     * Background task to handle Wiktionary lookups. This correctly shows and
     * hides the loading animation from the GUI thread before starting a
     * background query to the Wiktionary API. When finished, it transitions
     * back to the GUI thread where it updates with the newly-found entry.
     */
    private class LookupTask extends AsyncTask<String, String, String> {
        /**
         * Before jumping into background thread, start sliding in the
         * {@link ProgressBar}. We'll only show it once the animation finishes.
         */
        @Override
        protected void onPreExecute() {
            mTitleBar.startAnimation(mSlideIn);
        }

        /**
         * Perform the background query using {@link ExtendedWikiHelper}, which
         * may return an error message as the result.
         */
        @Override
        protected String doInBackground(String... args) {
            String query = args[0];
            String parsedText = null;

            try {
                // If query word is null, assume request for random word
                if (query == null) {
                    query = ExtendedWikiHelper.getRandomWord();
                }

                if (query != null) {
                    // Push our requested word to the title bar
                    publishProgress(query);
                    String wikiText = ExtendedWikiHelper.getPageContent(query, true);
                    parsedText = ExtendedWikiHelper.formatWikiText(wikiText);
                }
            } catch (ApiException e) {
                Log.e(TAG, "Problem making wiktionary request", e);
            } catch (ParseException e) {
                Log.e(TAG, "Problem making wiktionary request", e);
            }

            if (parsedText == null) {
                parsedText = getString(R.string.empty_result);
            }

            return parsedText;
        }

        /**
         * Our progress update pushes a title bar update.
         */
        @Override
        protected void onProgressUpdate(String... args) {
            String searchWord = args[0];
            setEntryTitle(searchWord);
        }

        /**
         * When finished, push the newly-found entry content into our
         * {@link WebView} and hide the {@link ProgressBar}.
         */
        @Override
        protected void onPostExecute(String parsedText) {
            mTitleBar.startAnimation(mSlideOut);
            mProgress.setVisibility(View.INVISIBLE);

            setEntryContent(parsedText);
        }
    }

    /**
     * Make the {@link ProgressBar} visible when our in-animation finishes.
     */
    public void onAnimationEnd(Animation animation) {
        mProgress.setVisibility(View.VISIBLE);
    }

    public void onAnimationRepeat(Animation animation) {
        // Not interested if the animation repeats
    }

    public void onAnimationStart(Animation animation) {
        // Not interested when the animation starts
    }
}



//src\com\example\android\wiktionary\SimpleWikiHelper.java


package com.example.android.wiktionary;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.util.Log;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;


public class SimpleWikiHelper {
    private static final String TAG = "SimpleWikiHelper";


    private static final String WIKTIONARY_PAGE =
            "http://en.wiktionary.org/w/api.php?action=query&prop=revisions&titles=%s&" +
            "rvprop=content&format=json%s";


    private static final String WIKTIONARY_EXPAND_TEMPLATES =
            "&rvexpandtemplates=true";

    /**
     * {@link StatusLine} HTTP status code when no server error has occurred.
     */
    private static final int HTTP_STATUS_OK = 200;


    private static byte[] sBuffer = new byte[512];


    private static String sUserAgent = null;


    public static class ApiException extends Exception {
        public ApiException(String detailMessage, Throwable throwable) {
            super(detailMessage, throwable);
        }

        public ApiException(String detailMessage) {
            super(detailMessage);
        }
    }


    public static class ParseException extends Exception {
        public ParseException(String detailMessage, Throwable throwable) {
            super(detailMessage, throwable);
        }
    }

    public static void prepareUserAgent(Context context) {
        try {
            // Read package name and version number from manifest
            PackageManager manager = context.getPackageManager();
            PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
            sUserAgent = String.format(context.getString(R.string.template_user_agent),
                    info.packageName, info.versionName);

        } catch(NameNotFoundException e) {
            Log.e(TAG, "Couldn't find package information in PackageManager", e);
        }
    }


    public static String getPageContent(String title, boolean expandTemplates)
            throws ApiException, ParseException {
        // Encode page title and expand templates if requested
        String encodedTitle = Uri.encode(title);
        String expandClause = expandTemplates ? WIKTIONARY_EXPAND_TEMPLATES : "";

        // Query the API for content
        String content = getUrlContent(String.format(WIKTIONARY_PAGE,
                encodedTitle, expandClause));
        try {
            // Drill into the JSON response to find the content body
            JSONObject response = new JSONObject(content);
            JSONObject query = response.getJSONObject("query");
            JSONObject pages = query.getJSONObject("pages");
            JSONObject page = pages.getJSONObject((String) pages.keys().next());
            JSONArray revisions = page.getJSONArray("revisions");
            JSONObject revision = revisions.getJSONObject(0);
            return revision.getString("*");
        } catch (JSONException e) {
            throw new ParseException("Problem parsing API response", e);
        }
    }


    protected static synchronized String getUrlContent(String url) throws ApiException {
        if (sUserAgent == null) {
            throw new ApiException("User-Agent string must be prepared");
        }

        // Create client and set our specific user-agent string
        HttpClient client = new DefaultHttpClient();
        HttpGet request = new HttpGet(url);
        request.setHeader("User-Agent", sUserAgent);

        try {
            HttpResponse response = client.execute(request);

            // Check if server response is valid
            StatusLine status = response.getStatusLine();
            if (status.getStatusCode() != HTTP_STATUS_OK) {
                throw new ApiException("Invalid response from server: " +
                        status.toString());
            }

            // Pull content stream from response
            HttpEntity entity = response.getEntity();
            InputStream inputStream = entity.getContent();

            ByteArrayOutputStream content = new ByteArrayOutputStream();

            // Read response into a buffered stream
            int readBytes = 0;
            while ((readBytes = inputStream.read(sBuffer)) != -1) {
                content.write(sBuffer, 0, readBytes);
            }

            // Return result from buffered stream
            return new String(content.toByteArray());
        } catch (IOException e) {
            throw new ApiException("Problem communicating with API", e);
        }
    }

}



//src\com\example\android\wiktionary\WordWidget.java


package com.example.android.wiktionary;

import com.example.android.wiktionary.SimpleWikiHelper.ApiException;
import com.example.android.wiktionary.SimpleWikiHelper.ParseException;

import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.IBinder;
import android.text.format.Time;
import android.util.Log;
import android.widget.RemoteViews;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Define a simple widget that shows the Wiktionary "Word of the day." To build
 * an update we spawn a background {@link Service} to perform the API queries.
 */
public class WordWidget extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // To prevent any ANR timeouts, we perform the update in a service
        context.startService(new Intent(context, UpdateService.class));
    }

    public static class UpdateService extends Service {
        @Override
        public void onStart(Intent intent, int startId) {
            // Build the widget update for today
            RemoteViews updateViews = buildUpdate(this);

            // Push update for this widget to the home screen
            ComponentName thisWidget = new ComponentName(this, WordWidget.class);
            AppWidgetManager manager = AppWidgetManager.getInstance(this);
            manager.updateAppWidget(thisWidget, updateViews);
        }

        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

        /**
         * Regular expression that splits "Word of the day" entry into word
         * name, word type, and the first description bullet point.
         */
        private static final String WOTD_PATTERN =
            "(?s)\\{\\{wotd\\|(.+?)\\|(.+?)\\|([^#\\|]+).*?\\}\\}";

        /**
         * Build a widget update to show the current Wiktionary
         * "Word of the day." Will block until the online API returns.
         */
        public RemoteViews buildUpdate(Context context) {
            // Pick out month names from resources
            Resources res = context.getResources();
            String[] monthNames = res.getStringArray(R.array.month_names);

            // Find current month and day
            Time today = new Time();
            today.setToNow();

            // Build the page title for today, such as "March 21"
            String pageName = res.getString(R.string.template_wotd_title,
                    monthNames[today.month], today.monthDay);
            String pageContent = null;

            try {
                // Try querying the Wiktionary API for today's word
                SimpleWikiHelper.prepareUserAgent(context);
                pageContent = SimpleWikiHelper.getPageContent(pageName, false);
            } catch (ApiException e) {
                Log.e("WordWidget", "Couldn't contact API", e);
            } catch (ParseException e) {
                Log.e("WordWidget", "Couldn't parse API response", e);
            }

            RemoteViews views = null;
            Matcher matcher = Pattern.compile(WOTD_PATTERN).matcher(pageContent);
            if (matcher.find()) {
                // Build an update that holds the updated widget contents
                views = new RemoteViews(context.getPackageName(), R.layout.widget_word);

                String wordTitle = matcher.group(1);
                views.setTextViewText(R.id.word_title, wordTitle);
                views.setTextViewText(R.id.word_type, matcher.group(2));
                views.setTextViewText(R.id.definition, matcher.group(3).trim());

                // When user clicks on widget, launch to Wiktionary definition page
                String definePage = String.format("%s://%s/%s", ExtendedWikiHelper.WIKI_AUTHORITY,
                        ExtendedWikiHelper.WIKI_LOOKUP_HOST, wordTitle);
                Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage));
                PendingIntent pendingIntent = PendingIntent.getActivity(context,
                        0 /* no requestCode */, defineIntent, 0 /* no flags */);
                views.setOnClickPendingIntent(R.id.widget, pendingIntent);

            } else {
                // Didn't find word of day, so show error message
                views = new RemoteViews(context.getPackageName(), R.layout.widget_message);
                views.setTextViewText(R.id.message, context.getString(R.string.widget_error));
            }
            return views;
        }
    }
}



//
//res\anim\slide_in.xml
<?xml version="1.0" encoding="utf-8"?>


<set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true">
    <translate
        android:fromXDelta="-26"
        android:toXDelta="0"
        android:duration="400" />
</set>



//res\anim\slide_out.xml
<?xml version="1.0" encoding="utf-8"?>


<set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true">
    <translate
        android:fromXDelta="0"
        android:toXDelta="-26"
        android:duration="400" />
</set>



//
//res\layout\about.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"
    android:padding="20dip">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:text="@string/app_descrip"
        android:textColor="?android:attr/textColorPrimaryInverse" />

    <TextView
        android:id="@+id/about_credits"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="20dip"
        android:textSize="16sp"
        android:text="@string/app_credits"
        android:autoLink="web"
        android:textColor="?android:attr/textColorPrimaryInverse" />

</LinearLayout>



//res\layout\lookup.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">

    <LinearLayout
        android:id="@+id/title_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center_vertical">

        <ProgressBar
            android:id="@+id/progress"
            android:layout_width="18dip"
            android:layout_height="18dip"
            android:layout_marginLeft="10dip"
            android:visibility="invisible"
            android:indeterminateOnly="true"
            android:indeterminateDrawable="@drawable/progress_spin"
            android:indeterminateBehavior="repeat"
            android:indeterminateDuration="3500" />

        <TextView
            android:id="@+id/title"
            android:layout_width="0dip"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:padding="10dip"
            style="@style/LookupTitle" />

    </LinearLayout>

    <WebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1" />

</LinearLayout>



//res\layout\widget_message.xml
<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    style="@style/WidgetBackground">

    <TextView
        android:id="@+id/message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dip"
        android:padding="10dip"
        android:gravity="center"
        android:text="@string/widget_loading"
        style="@style/Text.Loading" />

</LinearLayout>



//res\layout\widget_word.xml
<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusable="true"
    style="@style/WidgetBackground">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:src="@drawable/star_logo" />

    <TextView
        android:id="@+id/word_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="14dip"
        android:layout_marginBottom="1dip"
        android:includeFontPadding="false"
        android:singleLine="true"
        android:ellipsize="end"
        style="@style/Text.WordTitle" />

    <TextView
        android:id="@+id/word_type"
        android:layout_width="0dip"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/word_title"
        android:layout_toLeftOf="@id/icon"
        android:layout_alignBaseline="@id/word_title"
        android:paddingLeft="4dip"
        android:includeFontPadding="false"
        android:singleLine="true"
        android:ellipsize="end"
        style="@style/Text.WordType" />

    <TextView
        android:id="@+id/bullet"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/word_title"
        android:paddingRight="4dip"
        android:includeFontPadding="false"
        android:singleLine="true"
        style="@style/BulletPoint" />

    <TextView
        android:id="@+id/definition"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/word_title"
        android:layout_toRightOf="@id/bullet"
        android:paddingRight="5dip"
        android:paddingBottom="4dip"
        android:includeFontPadding="false"
        android:lineSpacingMultiplier="0.9"
        android:maxLines="4"
        android:fadingEdge="vertical"
        style="@style/Text.Definition" />

</RelativeLayout>



//
//res\menu\lookup.xml
<?xml version="1.0" encoding="utf-8"?>


<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/lookup_search"
        android:title="@string/lookup_search"
        android:icon="@android:drawable/ic_menu_search" />

    <item
        android:id="@+id/lookup_random"
        android:title="@string/lookup_random"
        android:icon="@drawable/ic_menu_shuffle" />

    <item
        android:id="@+id/lookup_about"
        android:title="@string/lookup_about"
        android:icon="@android:drawable/ic_menu_help" />

</menu>



//
//res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>


<resources>
    <string name="app_name">Wiktionary example</string>
    <string name="app_descrip">Example of a fast Wiktionary browser and Word-of-day widget</string>
    <string name="app_credits">"All dictionary content provided by Wiktionary under a GFDL license.  http://en.wiktionary.org\n\nIcon derived from Tango Desktop Project under a public domain license.  http://tango.freedesktop.org"</string>

    <string name="template_user_agent" translatable="false">"%1$s/%2$s (Linux; Android)"</string>
    <string name="template_wotd_title">"Wiktionary:Word of the day/%1$s %2$s"</string>
    <string name="template_define_url" translatable="false">"http://en.wiktionary.org/wiki/%s"</string>

    <string name="widget_name">Wiktionary</string>

    <string name="widget_loading">"Loading word\nof day\u2026"</string>
    <string name="widget_error">No word of day found</string>

    <string-array name="month_names">
        <item>January</item>
        <item>February</item>
        <item>March</item>
        <item>April</item>
        <item>May</item>
        <item>June</item>
        <item>July</item>
        <item>August</item>
        <item>September</item>
        <item>October</item>
        <item>November</item>
        <item>December</item>
    </string-array>


    <string name="search_label">Wiktionary search</string>
    <string name="search_hint">Define word</string>

    <string name="lookup_search">Search</string>
    <string name="lookup_random">Random</string>
    <string name="lookup_about">About</string>

    <string name="empty_result">No entry found for this word, or problem reading data.</string>

</resources>



//res\values\styles.xml
<?xml version="1.0" encoding="utf-8"?>


<resources>

    <style name="WidgetBackground">
        <item name="android:background">@drawable/widget_bg</item>
    </style>

    <style name="BulletPoint">
        <item name="android:textSize">13sp</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

    <style name="Text" />

    <style name="Text.Loading">
        <item name="android:textSize">14sp</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

    <style name="Text.WordTitle">
        <item name="android:textSize">16sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

    <style name="Text.WordType">
        <item name="android:textSize">14sp</item>
        <item name="android:textStyle">italic</item>
        <item name="android:textColor">@android:color/black</item>
    </style>

    <style name="Text.Definition">
        <item name="android:textSize">13sp</item>
        <item name="android:textColor">@android:color/black</item>
    </style>


    <style name="LookupProgress">
        <item name="android:indeterminateOnly">true</item>
        <item name="android:indeterminateDrawable">@drawable/progress_spin</item>
        <item name="android:indeterminateBehavior">repeat</item>
        <item name="android:indeterminateDuration">3500</item>
    </style>

    <style name="LookupTitle">
        <item name="android:textSize">30sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">?android:attr/textColorPrimary</item>
    </style>

</resources>



//res\values\themes.xml
<?xml version="1.0" encoding="utf-8"?>

<resources>
    <style name="LookupTheme" parent="@android:style/Theme.Light.NoTitleBar">
        <item name="android:windowBackground">@drawable/lookup_bg</item>
    </style>
</resources>



//
//res\xml\searchable.xml
<?xml version="1.0" encoding="utf-8"?>


<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/search_label"
    android:hint="@string/search_hint" />



//res\xml\widget_word.xml
<?xml version="1.0" encoding="utf-8"?>


<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="146dip"
    android:minHeight="72dip"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/widget_message" />

   

Utility class supporting the Facebook Object.

//package com.facebook.android;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog.Builder;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;


/**
 * Utility class supporting the Facebook Object.
 * 
 * @author ssoneff@facebook.com
 *
 */
final class Util {

    /**
     * Generate the multi-part post body providing the parameters and boundary
     * string
     * 
     * @param parameters the parameters need to be posted
     * @param boundary the random string as boundary
     * @return a string of the post body
     */
    public static String encodePostBody(Bundle parameters, String boundary) {
        if (parameters == null) return "";
        StringBuilder sb = new StringBuilder();
        
        for (String key : parameters.keySet()) {
            if (parameters.getByteArray(key) != null) {
              continue;
            }
          
            sb.append("Content-Disposition: form-data; name=\"" + key + 
                "\"\r\n\r\n" + parameters.getString(key));
            sb.append("\r\n" + "--" + boundary + "\r\n");
        }
        
        return sb.toString();
    }

    public static String encodeUrl(Bundle parameters) {
        if (parameters == null) {
          return "";
        }
        
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (String key : parameters.keySet()) {
            if (first) first = false; else sb.append("&");
            sb.append(URLEncoder.encode(key) + "=" +
                      URLEncoder.encode(parameters.getString(key)));
        }
        return sb.toString();
    }

    public static Bundle decodeUrl(String s) {
        Bundle params = new Bundle();
        if (s != null) {
            String array[] = s.split("&");
            for (String parameter : array) {
                String v[] = parameter.split("=");
                params.putString(URLDecoder.decode(v[0]),
                                 URLDecoder.decode(v[1]));
            }
        }
        return params;
    }

    /**
     * Parse a URL query and fragment parameters into a key-value bundle.
     * 
     * @param url the URL to parse
     * @return a dictionary bundle of keys and values
     */
    public static Bundle parseUrl(String url) {
        // hack to prevent MalformedURLException
        url = url.replace("fbconnect", "http"); 
        try {
            URL u = new URL(url);
            Bundle b = decodeUrl(u.getQuery());
            b.putAll(decodeUrl(u.getRef()));
            return b;
        } catch (MalformedURLException e) {
            return new Bundle();
        }
    }

    
 
    public static String openUrl(String url, String method, Bundle params) 
          throws MalformedURLException, IOException {
      // random string as boundary for multi-part http post
      String strBoundary = "3i2ndDfv2rTHiSisAbouNdArYfORhtTPEefj3q2f";
      String endLine = "\r\n";
   
      OutputStream os;

        if (method.equals("GET")) {
            url = url + "?" + encodeUrl(params);
        }
        Log.d("Facebook-Util", method + " URL: " + url);
        HttpURLConnection conn = 
            (HttpURLConnection) new URL(url).openConnection();
        conn.setRequestProperty("User-Agent", System.getProperties().
                getProperty("http.agent") + " FacebookAndroidSDK");
        if (!method.equals("GET")) {
            Bundle dataparams = new Bundle();
            for (String key : params.keySet()) {
                if (params.getByteArray(key) != null) {
                        dataparams.putByteArray(key, params.getByteArray(key));
                }
            }
          
            // use method override
            if (!params.containsKey("method")) {
              params.putString("method", method);             
            }
            
            if (params.containsKey("access_token")) {
              String decoded_token = URLDecoder.decode(params.getString("access_token"));
              params.putString("access_token", decoded_token);
            }
                     
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+strBoundary);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.connect();
            os = new BufferedOutputStream(conn.getOutputStream());
            
            os.write(("--" + strBoundary +endLine).getBytes());
            os.write((encodePostBody(params, strBoundary)).getBytes());
            os.write((endLine + "--" + strBoundary + endLine).getBytes());
            
            if (!dataparams.isEmpty()) {
              
                for (String key: dataparams.keySet()){
                    os.write(("Content-Disposition: form-data; filename=\"" + key + "\"" + endLine).getBytes());
                    os.write(("Content-Type: content/unknown" + endLine + endLine).getBytes());
                    os.write(dataparams.getByteArray(key));
                    os.write((endLine + "--" + strBoundary + endLine).getBytes());

                }            
            }
            os.flush();
        }
        
        String response = "";
        try {
          response = read(conn.getInputStream());
        } catch (FileNotFoundException e) {
            // Error Stream contains JSON that we can parse to a FB error
            response = read(conn.getErrorStream());
        }
        return response;
    }

    private static String read(InputStream in) throws IOException {
        StringBuilder sb = new StringBuilder();
        BufferedReader r = new BufferedReader(new InputStreamReader(in), 1000);
        for (String line = r.readLine(); line != null; line = r.readLine()) {
            sb.append(line);
        }
        in.close();
        return sb.toString();
    }

    public static void clearCookies(Context context) {
        // Edge case: an illegal state exception is thrown if an instance of 
        // CookieSyncManager has not be created.  CookieSyncManager is normally
        // created by a WebKit view, but this might happen if you start the 
        // app, restore saved state, and click logout before running a UI 
        // dialog in a WebView -- in which case the app crashes
        @SuppressWarnings("unused")
        CookieSyncManager cookieSyncMngr = 
            CookieSyncManager.createInstance(context);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.removeAllCookie();
    }


    public static JSONObject parseJson(String response) 
          throws JSONException, Exception {
        // Edge case: when sending a POST request to /[post_id]/likes
        // the return value is 'true' or 'false'. Unfortunately
        // these values cause the JSONObject constructor to throw
        // an exception.
        if (response.equals("false")) {
            throw new Exception("request failed");
        }
        if (response.equals("true")) {
            response = "{value : true}";
        }
        JSONObject json = new JSONObject(response);
        
        // errors set by the server are not consistent
        // they depend on the method and endpoint
        if (json.has("error")) {
            JSONObject error = json.getJSONObject("error");
//            throw new Exception("type");
        }
        if (json.has("error_code") && json.has("error_msg")) {
  //          throw new Exception(json.getString("error_msg"), "",
    //                Integer.parseInt(json.getString("error_code")));
        }
        if (json.has("error_code")) {
       //     throw new Exception("request failed", "",
         //           Integer.parseInt(json.getString("error_code")));
        }
        if (json.has("error_msg")) {
            throw new Exception(json.getString("error_msg"));
        }
        if (json.has("error_reason")) {
            throw new Exception(json.getString("error_reason"));
        }
        return json;
    }
    

    public static void showAlert(Context context, String title, String text) {
        Builder alertBuilder = new Builder(context);
        alertBuilder.setTitle(title);
        alertBuilder.setMessage(text);
        alertBuilder.create().show();
    }

}