Initial Contribution
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
new file mode 100644
index 0000000..9d5387e
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
@@ -0,0 +1,340 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*******************************************************************************
+*/ 
+ /** 
+  * A JNI interface for ICU converters.
+  *
+  * 
+  * @author Ram Viswanadha, IBM
+  */
+package com.ibm.icu4jni.charset;
+
+import com.ibm.icu4jni.common.ErrorCode;
+import com.ibm.icu4jni.converters.NativeConverter;
+
+
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.ByteBuffer;
+
+public final class CharsetDecoderICU extends CharsetDecoder{ 
+        
+
+    private static final int INPUT_OFFSET   = 0,
+                             OUTPUT_OFFSET  = 1,
+                             INVALID_BYTES  = 2,
+                             INPUT_HELD     = 3,
+                             LIMIT          = 4;
+    /* data is 3 element array where
+     * data[INPUT_OFFSET]   = on input contains the start of input and on output the number of input chars consumed
+     * data[OUTPUT_OFFSET]  = on input contains the start of output and on output the number of output bytes written
+     * data[INVALID_CHARS]  = number of invalid chars
+     * data[INPUT_HELD]     = number of input chars held in the converter's state
+     */
+    private int[] data = new int[LIMIT];
+    
+    /* handle to the ICU converter that is opened */
+    private long converterHandle=0;
+
+    
+    private  byte[] input = null;
+    private  char[] output= null;
+    
+    // These instance variables are
+    // always assigned in the methods
+    // before being used. This class
+    // inhrently multithread unsafe
+    // so we dont have to worry about
+    // synchronization
+    private int inEnd;
+    private int outEnd;
+    private int ec;
+    private int onUnmappableInput = NativeConverter.STOP_CALLBACK;;
+    private int onMalformedInput = NativeConverter.STOP_CALLBACK;;
+    private int savedInputHeldLen;
+    
+    /** 
+     * Constructs a new decoder for the given charset
+     * @param cs for which the decoder is created
+     * @param cHandle the address of ICU converter
+     * @exception RuntimeException
+     * @stable ICU 2.4
+     */
+    public CharsetDecoderICU(Charset cs,long cHandle){
+         super(cs,
+               NativeConverter.getAveCharsPerByte(cHandle),
+               NativeConverter.getMaxCharsPerByte(cHandle)
+               );
+                       
+         char[] sub = replacement().toCharArray();
+         ec = NativeConverter.setCallbackDecode(cHandle,
+                                                onMalformedInput,
+                                                onUnmappableInput,
+                                                sub, sub.length);
+         if(ErrorCode.isFailure(ec)){
+            throw ErrorCode.getException(ec);
+         }
+         // store the converter handle
+         converterHandle=cHandle;
+
+    }
+    
+    /**
+     * Sets this decoders replacement string. Substitutes the string in input if an
+     * umappable or illegal sequence is encountered
+     * @param newReplacement to replace the error bytes with
+     * @stable ICU 2.4
+     */    
+    protected void implReplaceWith(String newReplacement) {
+        if(converterHandle > 0){
+            if( newReplacement.length() > NativeConverter.getMaxBytesPerChar(converterHandle)) {
+                    throw new IllegalArgumentException();
+            }           
+            ec =NativeConverter.setSubstitutionChars(converterHandle,
+                                                    newReplacement.toCharArray(),
+                                                    newReplacement.length()
+                                                    );
+            if(ErrorCode.isFailure(ec)){
+                throw ErrorCode.getException(ec);
+            }
+        }
+     }
+    
+    /**
+     * Sets the action to be taken if an illegal sequence is encountered
+     * @param newAction action to be taken
+     * @exception IllegalArgumentException
+     * @stable ICU 2.4
+     */
+    protected final void implOnMalformedInput(CodingErrorAction newAction) {
+        if(newAction.equals(CodingErrorAction.IGNORE)){
+            onMalformedInput = NativeConverter.SKIP_CALLBACK;
+        }else if(newAction.equals(CodingErrorAction.REPLACE)){
+            onMalformedInput = NativeConverter.SUBSTITUTE_CALLBACK;
+        }else if(newAction.equals(CodingErrorAction.REPORT)){
+            onMalformedInput = NativeConverter.STOP_CALLBACK;
+        }
+        char[] sub = replacement().toCharArray();
+        //System.out.println(" setting callbacks mfi " + onMalformedInput +" umi " + onUnmappableInput);
+        ec = NativeConverter.setCallbackDecode(converterHandle, onMalformedInput, onUnmappableInput, sub, sub.length);
+        if(ErrorCode.isFailure(ec)){
+            throw ErrorCode.getException(ec);
+        } 
+    }
+    
+    /**
+     * Sets the action to be taken if an illegal sequence is encountered
+     * @param newAction action to be taken
+     * @exception IllegalArgumentException
+     * @stable ICU 2.4
+     */
+    protected final void implOnUnmappableCharacter(CodingErrorAction newAction) {
+        if(newAction.equals(CodingErrorAction.IGNORE)){
+            onUnmappableInput = NativeConverter.SKIP_CALLBACK;
+        }else if(newAction.equals(CodingErrorAction.REPLACE)){
+            onUnmappableInput = NativeConverter.SUBSTITUTE_CALLBACK;
+        }else if(newAction.equals(CodingErrorAction.REPORT)){
+            onUnmappableInput = NativeConverter.STOP_CALLBACK;
+        }
+        char[] sub = replacement().toCharArray();
+        ec = NativeConverter.setCallbackDecode(converterHandle,onMalformedInput, onUnmappableInput, sub, sub.length);
+        if(ErrorCode.isFailure(ec)){
+            throw ErrorCode.getException(ec);
+        } 
+    }
+    
+    /**
+     * Flushes any characters saved in the converter's internal buffer and
+     * resets the converter.
+     * @param out action to be taken
+     * @return result of flushing action and completes the decoding all input. 
+     *         Returns CoderResult.UNDERFLOW if the action succeeds.
+     * @stable ICU 2.4
+     */
+    protected final CoderResult implFlush(CharBuffer out) {
+       try{
+           
+           data[OUTPUT_OFFSET] = getArray(out);
+
+            ec=NativeConverter.flushByteToChar(
+                                            converterHandle,  /* Handle to ICU Converter */
+                                            output,           /* input array of chars */
+                                            outEnd,           /* input index+1 to be written */
+                                            data              /* contains data, inOff,outOff */
+                                            );
+                                      
+            
+            /* If we don't have room for the output, throw an exception*/
+            if (ErrorCode.isFailure(ec)) {
+                if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
+                    return CoderResult.OVERFLOW;
+                }else if (ec == ErrorCode.U_TRUNCATED_CHAR_FOUND ) {//CSDL: add this truncated character error handling
+                    if(data[INPUT_OFFSET]>0){
+                        return CoderResult.malformedForLength(data[INPUT_OFFSET]);
+                    }
+                }else {
+                    ErrorCode.getException(ec);
+                }
+            }
+            return CoderResult.UNDERFLOW;
+       }finally{
+            /* save the flushed data */
+            setPosition(out);
+            implReset();
+       }
+    }
+    
+    /**
+     * Resets the to Unicode mode of converter
+     * @stable ICU 2.4
+     */
+    protected void implReset() {
+        NativeConverter.resetByteToChar(converterHandle);
+        data[INPUT_OFFSET] = 0;
+        data[OUTPUT_OFFSET] = 0;
+        data[INVALID_BYTES] = 0;
+        data[INPUT_HELD] = 0;
+        savedInputHeldLen = 0;
+        output = null;
+        input = null;
+    }
+      
+    /**
+     * Decodes one or more bytes. The default behaviour of the converter
+     * is stop and report if an error in input stream is encountered. 
+     * To set different behaviour use @see CharsetDecoder.onMalformedInput()
+     * This  method allows a buffer by buffer conversion of a data stream.  
+     * The state of the conversion is saved between calls to convert.  
+     * Among other things, this means multibyte input sequences can be 
+     * split between calls. If a call to convert results in an Error, the 
+     * conversion may be continued by calling convert again with suitably 
+     * modified parameters.All conversions should be finished with a call to 
+     * the flush method.
+     * @param in buffer to decode
+     * @param out buffer to populate with decoded result
+     * @return result of decoding action. Returns CoderResult.UNDERFLOW if the decoding
+     *         action succeeds or more input is needed for completing the decoding action.
+     * @stable ICU 2.4
+     */
+    protected CoderResult decodeLoop(ByteBuffer in,CharBuffer out){
+
+        if(!in.hasRemaining()){
+            return CoderResult.UNDERFLOW;
+        }
+
+        data[INPUT_OFFSET] = getArray(in);
+        data[OUTPUT_OFFSET]= getArray(out);
+        data[INPUT_HELD] = 0;
+        
+        try{
+            /* do the conversion */
+            ec=NativeConverter.decode(
+                                converterHandle,  /* Handle to ICU Converter */
+                                input,            /* input array of bytes */
+                                inEnd,            /* last index+1 to be converted */
+                                output,           /* input array of chars */
+                                outEnd,           /* input index+1 to be written */
+                                data,             /* contains data, inOff,outOff */
+                                false             /* donot flush the data */
+                                );
+            
+
+            /* return an error*/
+            if(ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR){
+                return CoderResult.OVERFLOW;
+            }else if(ec==ErrorCode.U_INVALID_CHAR_FOUND){
+                return CoderResult.unmappableForLength(data[INVALID_BYTES]);
+            }else if(ec==ErrorCode.U_ILLEGAL_CHAR_FOUND){
+                return CoderResult.malformedForLength(data[INVALID_BYTES]);
+            }
+            /* decoding action succeded */
+            return CoderResult.UNDERFLOW;
+        }finally{
+            setPosition(in);
+            setPosition(out);
+        }
+    }
+    
+    /**
+     * Releases the system resources by cleanly closing ICU converter opened
+     * @stable ICU 2.4
+     */
+    protected void finalize()throws Throwable{
+        NativeConverter.closeConverter(converterHandle);
+        super.finalize();
+        converterHandle = 0;
+    }
+    
+    //------------------------------------------
+    // private utility methods
+    //------------------------------------------
+
+    private final int getArray(CharBuffer out){
+        if(out.hasArray()){
+            output = out.array();
+            outEnd = out.limit();
+            return out.position();
+        }else{
+            outEnd = out.remaining();
+            if(output==null || (outEnd > output.length)){
+                output = new char[outEnd];
+            }
+            //since the new 
+            // buffer start position 
+            // is 0
+            return 0;
+        }
+        
+    }
+    private  final int getArray(ByteBuffer in){
+        if(in.hasArray()){
+            input = in.array();
+            inEnd = in.limit();
+            return in.position()+savedInputHeldLen;/*exclude the number fo bytes held in previous conversion*/
+        }else{
+            inEnd = in.remaining();
+            if(input==null|| (inEnd > input.length)){ 
+                input = new byte[inEnd];
+            }
+            // save the current position
+            int pos = in.position();
+            in.get(input,0,inEnd);
+            // reset the position
+            in.position(pos);
+            // the start position  
+            // of the new buffer  
+            // is whatever is savedInputLen
+            return savedInputHeldLen;
+        }
+       
+    }
+    private final void setPosition(CharBuffer out){
+        if(out.hasArray()){
+            out.position(out.position() + data[OUTPUT_OFFSET]);
+        }else{
+            out.put(output,0,data[OUTPUT_OFFSET]);
+        }
+    }
+    private final void setPosition(ByteBuffer in){
+
+        // ok was there input held in the previous invocation of decodeLoop 
+        // that resulted in output in this invocation?
+        if(data[OUTPUT_OFFSET]>0 && savedInputHeldLen >0){
+            int len = in.position() + data[INPUT_OFFSET] + savedInputHeldLen;
+            in.position(len);   
+            savedInputHeldLen = data[INPUT_HELD];
+        }else{
+            in.position(in.position() + data[INPUT_OFFSET] + savedInputHeldLen);
+            savedInputHeldLen = data[INPUT_HELD];
+            in.position(in.position() - savedInputHeldLen);
+        }       
+    }
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java
new file mode 100644
index 0000000..cdc98a7
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java
@@ -0,0 +1,406 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                  *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+/** 
+ * A JNI interface for ICU converters.
+ *
+ * 
+ * @author Ram Viswanadha, IBM
+ */
+package com.ibm.icu4jni.charset;  
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+import com.ibm.icu4jni.common.ErrorCode;
+import com.ibm.icu4jni.converters.NativeConverter;
+
+public final class CharsetEncoderICU extends CharsetEncoder {
+
+    private static final int INPUT_OFFSET = 0,
+                             OUTPUT_OFFSET = 1,
+                             INVALID_CHARS  = 2,
+                             INPUT_HELD     = 3,
+                             LIMIT          = 4;
+    /* data is 3 element array where
+     * data[INPUT_OFFSET]   = on input contains the start of input and on output the number of input chars consumed
+     * data[OUTPUT_OFFSET]  = on input contains the start of output and on output the number of output bytes written
+     * data[INVALID_CHARS]  = number of invalid chars
+     * data[INPUT_HELD]     = number of input chars held in the converter's state
+     */
+    private int[] data = new int[LIMIT];
+    /* handle to the ICU converter that is opened */
+    private long converterHandle=0;
+
+    private char[] input = null;
+    private byte[] output = null;
+
+    // These instance variables are
+    // always assigned in the methods
+    // before being used. This class
+    // inhrently multithread unsafe
+    // so we dont have to worry about
+    // synchronization
+    private int inEnd;
+    private int outEnd;
+    private int ec;
+    private int savedInputHeldLen;
+    private int onUnmappableInput = NativeConverter.STOP_CALLBACK;;
+    private int onMalformedInput = NativeConverter.STOP_CALLBACK;;
+
+    /** 
+     * Construcs a new encoder for the given charset
+     * @param cs for which the decoder is created
+     * @param cHandle the address of ICU converter
+     * @param replacement the substitution bytes
+     * @stable ICU 2.4
+     */
+    public CharsetEncoderICU(Charset cs, long cHandle, byte[] replacement) {
+        super(
+            cs,
+            (float) NativeConverter.getAveBytesPerChar(cHandle),
+            (float) NativeConverter.getMaxBytesPerChar(cHandle),
+            replacement);
+        byte[] sub = replacement();
+        // The default callback action on unmappable input 
+        // or malformed input is to ignore so we set ICU converter
+        // callback to stop and report the error
+        ec = NativeConverter.setCallbackEncode( cHandle,
+                                                onMalformedInput,
+                                                onUnmappableInput,
+                                                sub, sub.length);
+        converterHandle = cHandle;
+        if (ErrorCode.isFailure(ec)) {
+            throw ErrorCode.getException(ec);
+        }
+    }
+
+    /**
+     * Sets this encoders replacement string. Substitutes the string in output if an
+     * umappable or illegal sequence is encountered
+     * @param newReplacement to replace the error chars with
+     * @stable ICU 2.4
+     */
+    protected void implReplaceWith(byte[] newReplacement) {
+        if (converterHandle != 0) {
+            if (newReplacement.length
+                > NativeConverter.getMaxBytesPerChar(converterHandle)) {
+                throw new IllegalArgumentException("Number of replacement Bytes are greater than max bytes per char");
+            }
+            ec = NativeConverter.setSubstitutionBytes(converterHandle,
+                                                      newReplacement,
+                                                      newReplacement.length);
+            if (ErrorCode.isFailure(ec)) {
+                throw ErrorCode.getException(ec);
+            }
+        }
+    }
+
+    /**
+     * Sets the action to be taken if an illegal sequence is encountered
+     * @param newAction action to be taken
+     * @exception IllegalArgumentException
+     * @stable ICU 2.4
+     */
+    protected void implOnMalformedInput(CodingErrorAction newAction) {
+        onMalformedInput = NativeConverter.STOP_CALLBACK;
+
+        if (newAction.equals(CodingErrorAction.IGNORE)) {
+            onMalformedInput = NativeConverter.SKIP_CALLBACK;
+        } else if (newAction.equals(CodingErrorAction.REPLACE)) {
+            onMalformedInput = NativeConverter.SUBSTITUTE_CALLBACK;
+        }
+        byte[] sub = replacement();
+        ec = NativeConverter.setCallbackEncode(converterHandle, onMalformedInput, onUnmappableInput, sub, sub.length);
+        if (ErrorCode.isFailure(ec)) {
+            throw ErrorCode.getException(ec);
+        }
+
+    }
+
+    /**
+     * Sets the action to be taken if an illegal sequence is encountered
+     * @param newAction action to be taken
+     * @exception IllegalArgumentException
+     * @stable ICU 2.4
+     */
+    protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
+        onUnmappableInput = NativeConverter.STOP_CALLBACK;
+
+        if (newAction.equals(CodingErrorAction.IGNORE)) {
+            onUnmappableInput = NativeConverter.SKIP_CALLBACK;
+        } else if (newAction.equals(CodingErrorAction.REPLACE)) {
+            onUnmappableInput = NativeConverter.SUBSTITUTE_CALLBACK;
+        }
+        byte[] sub = replacement();
+        ec = NativeConverter.setCallbackEncode(converterHandle, onMalformedInput, onUnmappableInput, sub, sub.length);
+        if (ErrorCode.isFailure(ec)) {
+            throw ErrorCode.getException(ec);
+        }
+    }
+
+    /**
+     * Flushes any characters saved in the converter's internal buffer and
+     * resets the converter.
+     * @param out action to be taken
+     * @return result of flushing action and completes the decoding all input. 
+     *       Returns CoderResult.UNDERFLOW if the action succeeds.
+     * @stable ICU 2.4
+     */
+    protected CoderResult implFlush(ByteBuffer out) {
+        try {
+            data[OUTPUT_OFFSET] = getArray(out);
+            ec = NativeConverter.flushCharToByte(converterHandle,/* Handle to ICU Converter */
+                                                 output, /* output array of chars */
+                                                 outEnd, /* output index+1 to be written */
+                                                 data /* contains data, inOff,outOff */
+                                                );
+
+            /* If we don't have room for the output, throw an exception*/
+            if (ErrorCode.isFailure(ec)) {
+                if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
+                    return CoderResult.OVERFLOW;
+                }else if (ec == ErrorCode.U_TRUNCATED_CHAR_FOUND) {//CSDL: add this truncated character error handling
+                    if(data[INPUT_OFFSET]>0){
+                        return CoderResult.malformedForLength(data[INPUT_OFFSET]);
+                    }
+                }else {
+                    ErrorCode.getException(ec);
+                }
+            }
+            return CoderResult.UNDERFLOW;
+        } finally {
+            setPosition(out);
+            implReset();
+        }
+    }
+
+    /**
+     * Resets the from Unicode mode of converter
+     * @stable ICU 2.4
+     */
+    protected void implReset() {
+        NativeConverter.resetCharToByte(converterHandle);
+        data[INPUT_OFFSET] = 0;
+        data[OUTPUT_OFFSET] = 0;
+        data[INVALID_CHARS] = 0;
+        data[INPUT_HELD] = 0;
+        savedInputHeldLen = 0;
+    }
+
+    /**
+     * Encodes one or more chars. The default behaviour of the
+     * converter is stop and report if an error in input stream is encountered.
+     * To set different behaviour use @see CharsetEncoder.onMalformedInput()
+     * @param in buffer to decode
+     * @param out buffer to populate with decoded result
+     * @return result of decoding action. Returns CoderResult.UNDERFLOW if the decoding
+     *       action succeeds or more input is needed for completing the decoding action.
+     * @stable ICU 2.4
+     */
+    protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
+
+        if (!in.hasRemaining()) {
+            return CoderResult.UNDERFLOW;
+        }
+
+        data[INPUT_OFFSET] = getArray(in);
+        data[OUTPUT_OFFSET]= getArray(out);
+        data[INPUT_HELD] = 0;
+        // BEGIN android-added
+        data[INVALID_CHARS] = 0; // Make sure we don't see earlier errors. 
+        // END android added
+        
+        try {
+            /* do the conversion */
+            ec = NativeConverter.encode(converterHandle,/* Handle to ICU Converter */
+                                        input, /* input array of bytes */
+                                        inEnd, /* last index+1 to be converted */
+                                        output, /* output array of chars */
+                                        outEnd, /* output index+1 to be written */
+                                        data, /* contains data, inOff,outOff */
+                                        false /* donot flush the data */
+                                        );
+            if (ErrorCode.isFailure(ec)) {
+                /* If we don't have room for the output return error */
+                if (ec == ErrorCode.U_BUFFER_OVERFLOW_ERROR) {
+                    return CoderResult.OVERFLOW;
+                } else if (ec == ErrorCode.U_INVALID_CHAR_FOUND) {
+                    return CoderResult.unmappableForLength(data[INVALID_CHARS]);
+                } else if (ec == ErrorCode.U_ILLEGAL_CHAR_FOUND) {
+                    // in.position(in.position() - 1);
+                    return CoderResult.malformedForLength(data[INVALID_CHARS]);
+                }
+            }
+            return CoderResult.UNDERFLOW;
+        } finally {
+            /* save state */
+            setPosition(in);
+            setPosition(out);
+        }
+    }
+
+    /**
+     * Ascertains if a given Unicode character can 
+     * be converted to the target encoding
+     *
+     * @param  c the character to be converted
+     * @return true if a character can be converted
+     * @stable ICU 2.4
+     * 
+     */
+    public boolean canEncode(char c) {
+        return canEncode((int) c);
+    }
+
+    /**
+     * Ascertains if a given Unicode code point (32bit value for handling surrogates)
+     * can be converted to the target encoding. If the caller wants to test if a
+     * surrogate pair can be converted to target encoding then the
+     * responsibility of assembling the int value lies with the caller.
+     * For assembling a code point the caller can use UTF16 class of ICU4J and do something like:
+     * <pre>
+     * while(i<mySource.length){
+     *      if(UTF16.isLeadSurrogate(mySource[i])&& i+1< mySource.length){
+     *          if(UTF16.isTrailSurrogate(mySource[i+1])){
+     *              int temp = UTF16.charAt(mySource,i,i+1,0);
+     *              if(!((CharsetEncoderICU) myConv).canEncode(temp)){
+     *          passed=false;
+     *              }
+     *              i++;
+     *              i++;
+     *          }
+     *     }
+     * }
+     * </pre>
+     * or
+     * <pre>
+     * String src = new String(mySource);
+     * int i,codepoint;
+     * boolean passed = false;
+     * while(i<src.length()){
+     *    codepoint = UTF16.charAt(src,i);
+     *    i+= (codepoint>0xfff)? 2:1;
+     *    if(!(CharsetEncoderICU) myConv).canEncode(codepoint)){
+     *        passed = false;
+     *    }
+     * }
+     * </pre>
+     *
+     * @param codepoint Unicode code point as int value
+     * @return true if a character can be converted
+     * @obsolete ICU 2.4
+     * @deprecated ICU 3.4
+     */
+    public boolean canEncode(int codepoint) {
+        return NativeConverter.canEncode(converterHandle, codepoint);
+    }
+
+    /**
+     * Releases the system resources by cleanly closing ICU converter opened
+     * @exception Throwable exception thrown by super class' finalize method
+     * @stable ICU 2.4
+     */
+    protected void finalize() throws Throwable {
+        NativeConverter.closeConverter(converterHandle);
+        super.finalize();
+        converterHandle=0;
+    }
+
+    //------------------------------------------
+    // private utility methods
+    //------------------------------------------
+    private final int getArray(ByteBuffer out) {
+        if(out.hasArray()){
+            output = out.array();
+            outEnd = out.limit();
+            return out.position();
+        }else{
+            outEnd = out.remaining();
+            if(output==null || (outEnd > output.length)){
+                output = new byte[outEnd];
+            }
+            //since the new 
+            // buffer start position 
+            // is 0
+            return 0;
+        }
+    }
+
+    private final int getArray(CharBuffer in) {
+        if(in.hasArray()){
+            input = in.array();
+            inEnd = in.limit();
+            return in.position()+savedInputHeldLen;/*exclude the number fo bytes held in previous conversion*/
+        }else{
+            inEnd = in.remaining();
+            if(input==null|| (inEnd > input.length)){ 
+                input = new char[inEnd];
+            }
+            // save the current position
+            int pos = in.position();
+            in.get(input,0,inEnd);
+            // reset the position
+            in.position(pos);
+            // the start position  
+            // of the new buffer  
+            // is whatever is savedInputLen
+            return savedInputHeldLen;
+        }
+
+    }
+    private final void setPosition(ByteBuffer out) {
+        
+        if (out.hasArray()) {
+            // in getArray method we accessed the 
+            // array backing the buffer directly and wrote to 
+            // it, so just just set the position and return.
+            // This is done to avoid the creation of temp array.
+            out.position(out.position() + data[OUTPUT_OFFSET] );
+        } else {
+            out.put(output, 0, data[OUTPUT_OFFSET]);
+        }
+    }
+    private final void setPosition(CharBuffer in){
+
+// BEGIN android-removed
+//        // was there input held in the previous invocation of encodeLoop 
+//        // that resulted in output in this invocation?
+//        if(data[OUTPUT_OFFSET]>0 && savedInputHeldLen>0){
+//            int len = in.position() + data[INPUT_OFFSET] + savedInputHeldLen;
+//            in.position(len);   
+//            savedInputHeldLen = data[INPUT_HELD];
+//        }else{
+//            in.position(in.position() + data[INPUT_OFFSET] + savedInputHeldLen);
+//            savedInputHeldLen = data[INPUT_HELD];
+//            in.position(in.position() - savedInputHeldLen);
+//        }     
+// END android-removed
+
+// BEGIN android-added
+        // Slightly rewired original code to make it cleaner. Also
+        // added a fix for the problem where input charatcers got
+        // lost when invalid characters were encountered. Not sure
+        // what happens when data[INVALID_CHARS] is > 1, though,
+        // since we never saw that happening.
+        int len = in.position() + data[INPUT_OFFSET] + savedInputHeldLen;
+        len -= data[INVALID_CHARS]; // Otherwise position becomes wrong.
+        in.position(len);   
+        savedInputHeldLen = data[INPUT_HELD];
+        // was there input held in the previous invocation of encodeLoop 
+        // that resulted in output in this invocation?
+        if(!(data[OUTPUT_OFFSET]>0 && savedInputHeldLen>0)){
+            in.position(in.position() - savedInputHeldLen);
+        }     
+// END android-added
+    }
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetICU.java b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetICU.java
new file mode 100644
index 0000000..cc0e04a
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetICU.java
@@ -0,0 +1,128 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*******************************************************************************
+*/ 
+
+package com.ibm.icu4jni.charset;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.ibm.icu4jni.common.ErrorCode;
+import com.ibm.icu4jni.converters.NativeConverter;
+
+
+
+public final class CharsetICU extends Charset{
+    private String icuCanonicalName;
+    /**
+     * Constructor to create a the CharsetICU object
+     * @param canonicalName the canonical name as a string
+     * @param aliases the alias set as an array of strings
+     * @stable ICU 2.4
+     */
+    protected CharsetICU(String canonicalName, String icuCanonName, String[] aliases) {
+         super(canonicalName,aliases);
+         icuCanonicalName = icuCanonName;
+        
+    }
+    /**
+     * Returns a new decoder instance of this charset object
+     * @return a new decoder object
+     * @stable ICU 2.4
+     */
+    public CharsetDecoder newDecoder(){
+        // the arrays are locals and not
+        // instance variables since the
+        // methods on this class need to 
+        // be thread safe
+        long converterHandle = NativeConverter.openConverter(icuCanonicalName);
+        return new CharsetDecoderICU(this,converterHandle);
+    };
+    
+    // hardCoded list of replacement bytes
+    private static final Map subByteMap = new HashMap();
+    static{
+        subByteMap.put("UTF-32",new byte[]{0x00, 0x00, (byte)0xfe, (byte)0xff});
+        subByteMap.put("ibm-16684_P110-2003",new byte[]{0x40, 0x40}); // make \u3000 the sub char
+        subByteMap.put("ibm-971_P100-1995",new byte[]{(byte)0xa1, (byte)0xa1}); // make \u3000 the sub char
+    }
+    /**
+     * Returns a new encoder object of the charset
+     * @return a new encoder
+     * @stable ICU 2.4
+     */
+    public CharsetEncoder newEncoder(){
+        // the arrays are locals and not
+        // instance variables since the
+        // methods on this class need to 
+        // be thread safe
+        long converterHandle = NativeConverter.openConverter(icuCanonicalName);
+        
+        //According to the contract all converters should have non-empty replacement
+        byte[] replacement = NativeConverter.getSubstitutionBytes(converterHandle);
+
+       try{
+            return new CharsetEncoderICU(this,converterHandle, replacement);
+        }catch(IllegalArgumentException ex){
+            // work around for the non-sensical check in the nio API that
+            // a substitution character must be mappable while decoding!!
+            replacement = (byte[])subByteMap.get(icuCanonicalName);
+            if(replacement==null){
+                replacement = new byte[NativeConverter.getMinBytesPerChar(converterHandle)];
+                for(int i=0; i<replacement.length; i++){
+                    replacement[i]= 0x3f;
+                }
+            }
+            NativeConverter.setSubstitutionBytes(converterHandle, replacement, replacement.length);
+            return new CharsetEncoderICU(this,converterHandle, replacement);
+        }
+    } 
+    
+    /**
+     * Ascertains if a charset is a sub set of this charset
+     * @param cs charset to test
+     * @return true if the given charset is a subset of this charset
+     * @stable ICU 2.4
+     * 
+     * //CSDL: major changes by Jack
+     */
+    public boolean contains(Charset cs){
+        if (null == cs) {
+        return false;
+        } else if (this.equals(cs)) {
+            return true;
+        }
+        
+        long converterHandle1 = 0;
+        long converterHandle2 = 0;
+
+        try {
+            converterHandle1 = NativeConverter.openConverter(this.name());
+            if (converterHandle1 > 0) {
+                converterHandle2 = NativeConverter.openConverter(cs.name());
+                if (converterHandle2 > 0) {
+                    return NativeConverter.contains(converterHandle1,
+                            converterHandle2);
+                }
+            }
+            return false;
+        } finally {
+            if (0 != converterHandle1) {
+                NativeConverter.closeConverter(converterHandle1);
+                if (0 != converterHandle2) {
+                    NativeConverter.closeConverter(converterHandle2);
+                }
+            }
+        }
+    }
+}
+
+
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetProviderICU.java b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetProviderICU.java
new file mode 100644
index 0000000..42d9f99
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/charset/CharsetProviderICU.java
@@ -0,0 +1,116 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*******************************************************************************
+*/ 
+
+package com.ibm.icu4jni.charset;
+
+import java.nio.charset.Charset;
+import java.nio.charset.spi.CharsetProvider;
+import java.util.*;
+import java.util.Iterator;
+import com.ibm.icu4jni.converters.NativeConverter;
+
+public final class CharsetProviderICU extends CharsetProvider{
+    
+    /**
+     * Constructs a CharsetProviderICU object 
+     * @stable ICU 2.4
+     */
+    public CharsetProviderICU(){
+    }
+    
+    /**
+     * Constructs a charset for the given charset name
+     * @param charsetName charset name
+     * @return charset objet for the given charset name
+     * @stable ICU 2.4
+     */
+    public final Charset charsetForName(String charsetName) {
+        // get the canonical name    
+        String icuCanonicalName = NativeConverter.getICUCanonicalName(charsetName);      
+
+        // create the converter object and return it
+        if(icuCanonicalName==null || icuCanonicalName.length()==0){
+            // this would make the Charset API to throw 
+            // unsupported encoding exception
+            return null;
+        }
+        
+        // BEGIN android-added
+        try{
+            long cn = NativeConverter.openConverter(icuCanonicalName);
+            NativeConverter.closeConverter(cn);
+        }catch (RuntimeException re) {
+            // unsupported encoding. let the charset api throw an 
+            // UnsupportedEncodingException
+            return null;
+        }
+        // END android-added
+        
+        return getCharset(icuCanonicalName);
+    }
+    private final Charset getCharset(String icuCanonicalName){
+       String[] aliases = (String[])NativeConverter.getAliases(icuCanonicalName);    
+       String canonicalName = NativeConverter.getJavaCanonicalName(icuCanonicalName);
+       return (new CharsetICU(canonicalName,icuCanonicalName, aliases));  
+    }
+    /**
+     * Adds an entry to the given map whose key is the charset's 
+     * canonical name and whose value is the charset itself. 
+     * @param map a map to receive charset objects and names
+     * @stable ICU 2.4
+     */
+    public final void putCharsets(Map map) {
+        // Get the available converter canonical names and aliases    
+        String[] charsets = NativeConverter.getAvailable();        
+        for(int i=0; i<charsets.length;i++){           
+            // store the charsets and aliases in a Map    
+            if (!map.containsKey(charsets[i])){
+                map.put(charsets[i], charsetForName(charsets[i]));
+            }
+        }
+    }
+    /**
+     * Class that implements the iterator for charsets
+     * @stable ICU 2.4
+     */
+    protected final class CharsetIterator implements Iterator{
+      private String[] names;
+      private int currentIndex;
+      protected CharsetIterator(String[] strs){
+        names = strs;
+        currentIndex=0;
+      }
+      public boolean hasNext(){
+        return (currentIndex< names.length);
+      }
+      public Object next(){
+        if(currentIndex<names.length){
+              return charsetForName(names[currentIndex++]);
+        }else{
+              throw new NoSuchElementException();
+        }
+      }
+      public void remove() {
+            throw new UnsupportedOperationException();
+      }
+    }
+      
+
+    /**
+     * Returns an iterator for the available charsets
+     * @return Iterator the charset name iterator
+     * @stable ICU 2.4
+     */
+    public final Iterator charsets(){
+          String[] charsets = NativeConverter.getAvailable();
+          Iterator iter = new CharsetIterator(charsets);
+          return iter;
+    }
+     
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/common/ErrorCode.java b/libcore/icu/src/main/java/com/ibm/icu4jni/common/ErrorCode.java
new file mode 100644
index 0000000..023f165
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/common/ErrorCode.java
@@ -0,0 +1,205 @@
+/**
+******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and   *
+* others. All Rights Reserved.                                               *
+******************************************************************************
+*
+******************************************************************************
+*/
+
+package com.ibm.icu4jni.common;
+
+/**
+* Error exception class mapping ICU error codes of the enum UErrorCode
+* @author syn wee quek
+* @internal
+*/   
+public final class ErrorCode extends Exception
+{ 
+
+  // public methods --------------------------------------------------------
+  
+  /**
+  * Generic mapping from the error codes to java default exceptions.
+  * @param error error code
+  * @return java default exception that maps to the argument error code, 
+  *         otherwise if error is not a valid error code, null is returned.
+  * @stable ICU 2.4
+  */
+  public static final RuntimeException getException(int error)
+  {
+    if (error <= U_ZERO_ERROR && error >= U_ERROR_LIMIT) {
+      return null;
+    }
+    String errorname = ERROR_NAMES_[U_ILLEGAL_ARGUMENT_ERROR];
+    switch (error) {
+      case U_ILLEGAL_ARGUMENT_ERROR :
+        return new IllegalArgumentException(errorname);
+      case U_INDEX_OUTOFBOUNDS_ERROR :
+        return new ArrayIndexOutOfBoundsException(errorname);
+      case U_BUFFER_OVERFLOW_ERROR :
+        return new ArrayIndexOutOfBoundsException(errorname);
+      case U_UNSUPPORTED_ERROR :
+        return new UnsupportedOperationException(errorname);
+      default :
+        return new RuntimeException(errorname);
+    }
+  }
+  
+  // public static data member ---------------------------------------------
+  
+  /**
+  * Start of information results (semantically successful) 
+  */
+  public static final int U_ERROR_INFO_START = -128;
+  /** 
+  * A resource bundle lookup returned a fallback result (not an error) 
+  */
+  public static final int U_USING_FALLBACK_ERROR = -128;
+  /**
+  * A resource bundle lookup returned a result from the root locale (not an 
+  * error) 
+  */
+  public static final int U_USING_DEFAULT_ERROR = -127;
+  /**
+  * A SafeClone operation required allocating memory (informational 
+  * only 
+  */
+  public static final int U_SAFECLONE_ALLOCATED_ERROR = -126;
+  /**
+  * This must always be the last warning value to indicate the limit for 
+  * UErrorCode warnings (last warning code +1) 
+  */
+  public static final int U_ERROR_INFO_LIMIT = -125;
+  
+  /**
+  * No error, no warning
+  */
+  public static final int U_ZERO_ERROR = 0;
+  /**
+  * Start of codes indicating failure
+  */
+  public static final int U_ILLEGAL_ARGUMENT_ERROR = 1;
+  public static final int U_MISSING_RESOURCE_ERROR = 2;
+  public static final int U_INVALID_FORMAT_ERROR = 3;
+  public static final int U_FILE_ACCESS_ERROR = 4;
+  /**
+  * Indicates a bug in the library code
+  */
+  public static final int U_INTERNAL_PROGRAM_ERROR = 5;
+  public static final int U_MESSAGE_PARSE_ERROR = 6;
+  /**
+  * Memory allocation error
+  */
+  public static final int U_MEMORY_ALLOCATION_ERROR = 7;
+  public static final int U_INDEX_OUTOFBOUNDS_ERROR = 8;
+  /**
+  * Equivalent to Java ParseException
+  */
+  public static final int U_PARSE_ERROR = 9;
+  /**
+  * In the Character conversion routines: Invalid character or sequence was 
+  * encountered
+  */
+  public static final int U_INVALID_CHAR_FOUND = 10;
+  /**
+  * In the Character conversion routines: More bytes are required to complete 
+  * the conversion successfully
+  */
+  public static final int U_TRUNCATED_CHAR_FOUND = 11;
+  /**
+  * In codeset conversion: a sequence that does NOT belong in the codepage has 
+  * been encountered
+  */
+  public static final int U_ILLEGAL_CHAR_FOUND = 12;
+  /**
+  * Conversion table file found, but corrupted
+  */
+  public static final int U_INVALID_TABLE_FORMAT = 13;
+  /**
+  * Conversion table file not found
+  */
+  public static final int U_INVALID_TABLE_FILE = 14;
+  /**
+  * A result would not fit in the supplied buffer
+  */
+  public static final int U_BUFFER_OVERFLOW_ERROR = 15;
+  /**
+  * Requested operation not supported in current context
+  */
+  public static final int U_UNSUPPORTED_ERROR = 16;
+  /**
+  * an operation is requested over a resource that does not support it
+  */
+  public static final int U_RESOURCE_TYPE_MISMATCH = 17;
+  /**
+  * ISO-2022 illlegal escape sequence 
+  */
+  public static final int U_ILLEGAL_ESCAPE_SEQUENCE = 18;
+  /**
+  * ISO-2022 unsupported escape sequence
+  */
+  public static final int U_UNSUPPORTED_ESCAPE_SEQUENCE = 19;
+  /** 
+  * No space available for in-buffer expansion for Arabic shaping 
+  */
+  public static final int U_NO_SPACE_AVAILABLE = 20;
+  /**
+  * This must always be the last value to indicate the limit for UErrorCode 
+  * (last error code +1) 
+  */
+  public static final int U_ERROR_LIMIT = 21;
+  /**
+  * Load library flag
+  */
+  public static boolean LIBRARY_LOADED = false;
+  
+  // private data member ----------------------------------------------------
+  
+  /**
+  * Array of error code names corresponding to the errorcodes.
+  * ie ERROR_NAMES_[0] = name of U_ZERO_ERROR
+  */
+  private static final String ERROR_NAMES_[] = { 
+    "U_ZERO_ERROR",               "U_ILLEGAL_ARGUMENT_ERROR", 
+    "U_MISSING_RESOURCE_ERROR",   "U_INVALID_FORMAT_ERROR", 
+    "U_FILE_ACCESS_ERROR",        "U_INTERNAL_PROGRAM_ERROR", 
+    "U_MESSAGE_PARSE_ERROR",      "U_MEMORY_ALLOCATION_ERROR",
+    "U_INDEX_OUTOFBOUNDS_ERROR",  "U_PARSE_ERROR",
+    "U_INVALID_CHAR_FOUND",       "U_TRUNCATED_CHAR_FOUND", 
+    "U_ILLEGAL_CHAR_FOUND",       "U_INVALID_TABLE_FORMAT",
+    "U_INVALID_TABLE_FILE",       "U_BUFFER_OVERFLOW_ERROR",
+    "U_UNSUPPORTED_ERROR",        "U_RESOURCE_TYPE_MISMATCH",
+    "U_ILLEGAL_ESCAPE_SEQUENCE",  "U_UNSUPPORTED_ESCAPE_SEQUENCE"
+  };
+  /**
+   * Returns the error name of the input error code
+   * @param ec int value of the error code
+   * @return String name of the error code
+   * @stable ICU 2.4
+   */
+  public static String getErrorName(int ec){
+    return ERROR_NAMES_[ec];
+  }
+  
+  /**
+   * Returns true if the input error code denotes success
+   * @param ec int value of the error code
+   * @return boolean 
+   * @stable ICU 2.4
+   */    
+  public static boolean isSuccess(int ec){
+    return (ec<=U_ZERO_ERROR);
+  }
+  
+  /**
+   * Returns true if the input error code denotes failure
+   * @param ec int value of the error code
+   * @return boolean
+   * @stable ICU 2.4
+   */
+  public static boolean isFailure(int ec){
+    return (ec>U_ZERO_ERROR);
+  }
+}
+
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/converters/NativeConverter.java b/libcore/icu/src/main/java/com/ibm/icu4jni/converters/NativeConverter.java
new file mode 100644
index 0000000..aa0cd26
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/converters/NativeConverter.java
@@ -0,0 +1,422 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*******************************************************************************
+*/ 
+
+package com.ibm.icu4jni.converters;
+
+/**
+ * Class for accessing the underlying JNI methods
+ * @internal ICU 2.4
+ */
+public final class NativeConverter{
+  
+    //Native methods
+    
+    /**
+     * Converts an array of bytes containing characters in an external
+     * encoding into an array of Unicode characters.  This  method allows
+     * a buffer by buffer conversion of a data stream.  The state of the
+     * conversion is saved between calls to convert.  Among other things,
+     * this means multibyte input sequences can be split between calls.
+     * If a call to convert results in an Error, the conversion may be
+     * continued by calling convert again with suitably modified parameters.
+     * All conversions should be finished with a call to the flush method.
+     *
+     * @param converterHandle Address of converter object created by C code
+     * @param input byte array containing text to be converted.
+     * @param inEnd stop conversion at this offset in input array (exclusive).
+     * @param output character array to receive conversion result.
+     * @param outEnd stop writing to output array at this offset (exclusive).
+     * @param data integer array containing the following data    
+     *        data[0] = inputOffset
+     *        data[1] = outputOffset
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */
+     
+    public static final native int convertByteToChar( long converterHandle,
+                                   byte[] input, int inEnd,
+                                   char[] output, int outEnd,
+                                   int[] data,
+                                   boolean flush);
+    /**
+     * Converts an array of bytes containing characters in an external
+     * encoding into an array of Unicode characters.  This  method allows
+     * a buffer by buffer conversion of a data stream.  The state of the
+     * conversion is saved between calls to convert.  Among other things,
+     * this means multibyte input sequences can be split between calls.
+     * If a call to convert results in an Error, the conversion may be
+     * continued by calling convert again with suitably modified parameters.
+     * All conversions should be finished with a call to the flush method.
+     *
+     * @param converterHandle Address of converter object created by C code
+     * @param input byte array containing text to be converted.
+     * @param inEnd stop conversion at this offset in input array (exclusive).
+     * @param output character array to receive conversion result.
+     * @param outEnd stop writing to output array at this offset (exclusive).
+     * @param data integer array containing the following data    
+     *        data[0] = inputOffset
+     *        data[1] = outputOffset
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */
+    public static final native int decode( long converterHandle,
+                                   byte[] input, int inEnd,
+                                   char[] output, int outEnd,
+                                   int[] data,
+                                   boolean flush);
+    /**
+     * Converts an array of Unicode chars containing characters in an 
+     * external encoding into an array of bytes.  This  method allows
+     * a buffer by buffer conversion of a data stream.  The state of the
+     * conversion is saved between calls to convert.  Among other things,
+     * this means multibyte input sequences can be split between calls.
+     * If a call to convert results in an Error, the conversion may be
+     * continued by calling convert again with suitably modified parameters.
+     * All conversions should be finished with a call to the flush method.
+     *
+     * @param converterHandle Address of converter object created by C code
+     * @param input char array containing text to be converted.
+     * @param inEnd stop conversion at this offset in input array (exclusive).
+     * @param output byte array to receive conversion result.
+     * @param outEnd stop writing to output array at this offset (exclusive).
+     * @param data integer array containing the following data    
+     *        data[0] = inputOffset
+     *        data[1] = outputOffset
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */                             
+    public static final native int convertCharToByte(long converterHandle,
+                                   char[] input, int inEnd,
+                                   byte[] output, int outEnd,
+                                   int[] data,
+                                   boolean flush); 
+    /**
+     * Converts an array of Unicode chars containing characters in an 
+     * external encoding into an array of bytes.  This  method allows
+     * a buffer by buffer conversion of a data stream.  The state of the
+     * conversion is saved between calls to convert.  Among other things,
+     * this means multibyte input sequences can be split between calls.
+     * If a call to convert results in an Error, the conversion may be
+     * continued by calling convert again with suitably modified parameters.
+     * All conversions should be finished with a call to the flush method.
+     *
+     * @param converterHandle Address of converter object created by C code
+     * @param input char array containing text to be converted.
+     * @param inEnd stop conversion at this offset in input array (exclusive).
+     * @param output byte array to receive conversion result.
+     * @param outEnd stop writing to output array at this offset (exclusive).
+     * @param data integer array containing the following data    
+     *        data[0] = inputOffset
+     *        data[1] = outputOffset
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */                                     
+    public static final native int encode(long converterHandle,
+                                   char[] input, int inEnd,
+                                   byte[] output, int outEnd,
+                                   int[] data,
+                                   boolean flush);
+    /**
+     * Writes any remaining output to the output buffer and resets the
+     * converter to its initial state. 
+     *
+     * @param converterHandle Address of converter object created by C code
+     * @param output byte array to receive flushed output.
+     * @param outEnd stop writing to output array at this offset (exclusive).
+     * @return int error code returned by ICU
+     * @param data integer array containing the following data    
+     *        data[0] = inputOffset
+     *        data[1] = outputOffset
+     * @internal ICU 2.4
+     */ 
+    public static final native int flushCharToByte(long converterHandle,
+                                   byte[] output, 
+                                   int outEnd, 
+                                   int[] data);
+    /**
+     * Writes any remaining output to the output buffer and resets the
+     * converter to its initial state. 
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @param output char array to receive flushed output.
+     * @param outEnd stop writing to output array at this offset (exclusive).
+     * @return int error code returned by ICU
+     * @param data integer array containing the following data    
+     *        data[0] = inputOffset
+     *        data[1] = outputOffset
+     * @internal ICU 2.4
+     */     
+    public static final native int flushByteToChar(long converterHandle,
+                                   char[] output,  
+                                   int outEnd, 
+                                   int[] data);
+    
+    /**
+     * Open the converter with the specified encoding
+     *
+     * @param converterHandle long array for recieving the adress of converter object
+     *        created by the native code
+     * @param encoding string representing encoding
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */
+    public static final native long openConverter(String encoding);
+    /**
+     * Resets the ByteToChar (toUnicode) state of specified converter 
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @internal ICU 2.4
+     */
+    public static final native void resetByteToChar(long  converterHandle);
+    
+    /**
+     * Resets the CharToByte (fromUnicode) state of specified converter 
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @internal ICU 2.4
+     */
+    public static final native void resetCharToByte(long  converterHandle);
+    
+    /**
+     * Closes the specified converter and releases the resources
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @internal ICU 2.4
+     */
+    public static final native void closeConverter(long converterHandle);
+    
+    /**
+     * Sets the substitution Unicode chars of the specified converter used
+     * by encoder
+     * @param converterHandle Address of converter object created by the native code
+     * @param subChars array of chars to used for substitution
+     * @param length length of the array 
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */    
+    public static final native int setSubstitutionChars( long converterHandle,
+                                   char[] subChars,int length); 
+    /**
+     * Sets the substitution bytes of the specified converter used by decoder
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @param subChars array of bytes to used for substitution
+     * @param length length of the array 
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */    
+    public static final native int setSubstitutionBytes( long converterHandle,
+                                   byte[] subChars,int length);
+    /**
+     * Sets the substitution mode of CharToByte(fromUnicode) for the specified converter 
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @param mode to set the true/false
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */  
+    public static final native int setSubstitutionModeCharToByte(long converterHandle, 
+                                   boolean mode);
+    /**
+     * Sets the substitution mode of CharToByte(fromUnicode) for the specified converter 
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @param mode to set the true/false
+     * @return int error code returned by ICU
+     * @internal ICU 3.6
+     */  
+    public static final native int setSubstitutionModeByteToChar(long converterHandle, 
+                                   boolean mode);
+    /**
+     * Gets the numnber of invalid bytes in the specified converter object 
+     * for the last error that has occured
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @param length array of int to recieve length of the array 
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */
+    public static final native int countInvalidBytes(long converterHandle, int[] length);
+    
+    /**
+     * Gets the numnber of invalid chars in the specified converter object 
+     * for the last error that has occured
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @param length array of int to recieve length of the array 
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */   
+    public static final native int countInvalidChars(long converterHandle, int[] length);
+    
+    /**
+     * Gets the number of bytes needed for converting a char
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @return number of bytes needed
+     * @internal ICU 2.4
+     */ 
+    public static final native int getMaxBytesPerChar(long converterHandle);
+    
+    /**
+     * Gets the number of bytes needed for converting a char
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @return number of bytes needed
+     * @internal ICU 3.2
+     */ 
+    public static final native int getMinBytesPerChar(long converterHandle);
+    
+    /**
+     * Gets the average numnber of bytes needed for converting a char
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @return number of bytes needed
+     * @internal ICU 2.4
+     */ 
+    public static final native float getAveBytesPerChar(long converterHandle);
+   
+    /**
+     * Gets the number of chars needed for converting a byte
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @return number of bytes needed
+     * @internal ICU 2.4
+     */ 
+    public static final native int getMaxCharsPerByte(long converterHandle);
+   
+    /**
+     * Gets the average numnber of chars needed for converting a byte
+     *
+     * @param converterHandle Address of converter object created by the native code
+     * @return number of bytes needed
+     * @internal ICU 2.4
+     */ 
+    public static final native float getAveCharsPerByte(long converterHandle);
+    
+    //CSDL: added by Jack
+    /**
+     * Determines whether charset1 contains charset2.
+     */
+    public static final native boolean contains(long converterHandle1, long converterHandle2);
+    
+    public static final native byte[] getSubstitutionBytes(long converterHandle);
+    
+    /**
+     * Ascertains if a given Unicode code unit can 
+     * be converted to the target encoding
+     * @param converterHandle Address of converter object created by the native code
+     * @param  codeUnit the character to be converted
+     * @return true if a character can be converted
+     * @internal ICU 2.4
+     * 
+     */
+    public static final native boolean canEncode(long converterHandle,int codeUnit);
+    
+    /**
+     * Ascertains if a given a byte sequence can be converted to Unicode
+     * @param converterHandle Address of converter object created by the native code
+     * @param  bytes the bytes to be converted
+     * @return true if a character can be converted
+     * @internal ICU 2.4
+     * 
+     */
+    public static final native boolean canDecode(long converterHandle,byte[] bytes);
+    
+    /**
+     * Gets the number of converters installed in the current installation of ICU
+     * @return int number of converters installed
+     * @internal ICU 2.4
+     */
+    public static final native int countAvailable();
+    
+    /**
+     * Gets the canonical names of available converters 
+     * @return Object[] names as an object array
+     * @internal ICU 2.4
+     */
+    public static final native String[] getAvailable();
+    
+    /**
+     * Gets the number of aliases for a converter name
+     * @param enc encoding name
+     * @return number of aliases for the converter
+     * @internal ICU 2.4
+     */
+    public static final native int countAliases(String enc);
+    
+    /** 
+     * Gets the aliases associated with the converter name
+     * @param enc converter name
+     * @return converter names as elements in an object array
+     * @internal ICU 2.4
+     */
+    public static final native String[] getAliases(String enc);
+    
+    /**
+     * Gets the canonical name of the converter
+     * @param enc converter name
+     * @return canonical name of the converter
+     * @internal ICU 2.4
+     */
+    public static final native String getCanonicalName(String enc);
+    
+    /**
+     * Gets the canonical name of the converter as defined by Java
+     * @param enc converter name
+     * @return canonical name of the converter
+     * @internal ICU 3.4
+     */
+    public static final native String getICUCanonicalName(String enc);
+      
+    /**
+     * Gets the canonical name of the converter as defined by Java
+     * @param icuCanonicalName converter name
+     * @return canonical name of the converter
+     * @internal ICU 3.4
+     */
+    public static final native String getJavaCanonicalName(String icuCanonicalName);
+    
+    /**
+     * Sets the callback to Unicode for ICU conveter. The default behaviour of ICU callback
+     * is to call the specified callback function for both illegal and unmapped sequences.
+     * @param converterHandle Adress of the converter object created by native code
+     * @param mode call back mode to set. This is either STOP_CALLBACK, SKIP_CALLBACK or SUBSTITUE_CALLBACK
+     *        The converter performs the specified callback when an error occurs
+     * @param stopOnIllegal If true sets the alerts the converter callback to stop on an illegal sequence
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */
+    public static final native int setCallbackDecode(long converterHandle, int onMalformedInput, int onUnmappableInput, char[] subChars, int length);
+   
+    /**
+     * Sets the callback from Unicode for ICU conveter. The default behaviour of ICU callback
+     * is to call the specified callback function for both illegal and unmapped sequences.
+     * @param converterHandle Adress of the converter object created by native code
+     * @param mode call back mode to set. This is either STOP_CALLBACK, SKIP_CALLBACK or SUBSTITUE_CALLBACK
+     *        The converter performs the specified callback when an error occurs
+     * @param stopOnIllegal If true sets the alerts the converter callback to stop on an illegal sequence
+     * @return int error code returned by ICU
+     * @internal ICU 2.4
+     */
+    public static final native int setCallbackEncode(long converterHandle, int onMalformedInput, int onUnmappableInput, byte[] subBytes, int length);
+    
+    /**
+     * Returns a thread safe clone of the converter
+     * @internal ICU 2.4
+     */
+    public static final native long safeClone(long converterHandle);
+    
+    /** @internal ICU 2.4 */
+    public static final int STOP_CALLBACK = 0;//CodingErrorAction.REPORT
+    /** @internal ICU 2.4 */
+    public static final int SKIP_CALLBACK = 1;//CodingErrorAction.IGNORE
+    /** @internal ICU 2.4 */
+    public static final int SUBSTITUTE_CALLBACK = 2;//CodingErrorAction.REPLACE
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/lang/UCharacter.java b/libcore/icu/src/main/java/com/ibm/icu4jni/lang/UCharacter.java
new file mode 100644
index 0000000..ca278ac
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/lang/UCharacter.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.lang;
+
+import java.lang.Character.UnicodeBlock;
+
+public class UCharacter {
+
+    public static int digit(int codePoint, int radix) {
+        return digitImpl(codePoint, radix);
+    }
+
+    private static native int digitImpl(int codePoint, int radix);
+
+    public static int getType(int codePoint) {
+        return getTypeImpl(codePoint);
+    }
+
+    private static native int getTypeImpl(int codePoint);
+    
+    public static byte getDirectionality(int codePoint) {
+        return getDirectionalityImpl(codePoint);
+    }
+
+    private static native byte getDirectionalityImpl(int codePoint);
+    
+    public static boolean isMirrored(int codePoint) {
+        return isMirroredImpl(codePoint);
+    }
+
+    private static native boolean isMirroredImpl(int codePoint);
+    
+    public static int getNumericValue(int codePoint) {
+        return getNumericValueImpl(codePoint);
+    }
+
+    private static native int getNumericValueImpl(int codePoint);
+    
+    public static boolean isDefined(int codePoint) {
+        return isDefinedValueImpl(codePoint);
+    }
+
+    private static native boolean isDefinedValueImpl(int codePoint);
+
+    public static boolean isDigit(int codePoint) {
+        return isDigitImpl(codePoint);
+    }
+
+    private static native boolean isDigitImpl(int codePoint);
+
+    public static boolean isIdentifierIgnorable(int codePoint) {
+        return isIdentifierIgnorableImpl(codePoint);
+    }
+
+    private static native boolean isIdentifierIgnorableImpl(int codePoint);
+
+    public static boolean isLetter(int codePoint) {
+        return isLetterImpl(codePoint);
+    }
+
+    private static native boolean isLetterImpl(int codePoint);
+
+    public static boolean isLetterOrDigit(int codePoint) {
+        return isLetterOrDigitImpl(codePoint);
+    }
+
+    private static native boolean isLetterOrDigitImpl(int codePoint);
+
+    public static boolean isSpaceChar(int codePoint) {
+        return isSpaceCharImpl(codePoint);
+    }
+
+    private static native boolean isSpaceCharImpl(int codePoint);
+
+    public static boolean isTitleCase(int codePoint) {
+        return isTitleCaseImpl(codePoint);
+    }
+
+    private static native boolean isTitleCaseImpl(int codePoint);
+
+    public static boolean isUnicodeIdentifierPart(int codePoint) {
+        return isUnicodeIdentifierPartImpl(codePoint);
+    }
+
+    private static native boolean isUnicodeIdentifierPartImpl(int codePoint);
+
+    public static boolean isUnicodeIdentifierStart(int codePoint) {
+        return isUnicodeIdentifierStartImpl(codePoint);
+    }
+
+    private static native boolean isUnicodeIdentifierStartImpl(int codePoint);
+
+    public static boolean isWhitespace(int codePoint) {
+        return isWhitespaceImpl(codePoint);
+    }
+
+    private static native boolean isWhitespaceImpl(int codePoint);
+
+    public static int toLowerCase(int codePoint) {
+        return toLowerCaseImpl(codePoint);
+    }
+
+    private static native int toLowerCaseImpl(int codePoint);
+
+    public static int toTitleCase(int codePoint) {
+        return toTitleCaseImpl(codePoint);
+    }
+
+    private static native int toTitleCaseImpl(int codePoint);
+
+    public static int toUpperCase(int codePoint) {
+        return toUpperCaseImpl(codePoint);
+    }
+
+    private static native int toUpperCaseImpl(int codePoint);
+
+    public static boolean isUpperCase(int codePoint) {
+        return isUpperCaseImpl(codePoint);
+    }
+
+    private static native boolean isUpperCaseImpl(int codePoint);
+
+    public static boolean isLowerCase(int codePoint) {
+        return isLowerCaseImpl(codePoint);
+    }
+
+    private static native boolean isLowerCaseImpl(int codePoint);
+
+    public static int forName(String blockName) {
+        return forname(blockName);
+    }
+
+    private static native int forname(String blockName);
+
+    public static int of(int codePoint) {
+        return codeblock(codePoint);
+    }
+
+    private static native int codeblock(int codePoint);
+    
+    public static UnicodeBlock[] getBlockTable() {
+        /**
+         * The indices of the entries of this table correspond with the value
+         * of the ICU enum UBlockCode. When updating ICU it's necessary
+         * to check if there where any changes for the properties
+         * used by java.lang.Character. 
+         * The enum is defined in common/unicode/uchar.h
+         */
+        UnicodeBlock[] result = new UnicodeBlock[] { null,
+                UnicodeBlock.BASIC_LATIN,
+                UnicodeBlock.LATIN_1_SUPPLEMENT,
+                UnicodeBlock.LATIN_EXTENDED_A,
+                UnicodeBlock.LATIN_EXTENDED_B,
+                UnicodeBlock.IPA_EXTENSIONS,
+                UnicodeBlock.SPACING_MODIFIER_LETTERS,
+                UnicodeBlock.COMBINING_DIACRITICAL_MARKS,
+                UnicodeBlock.GREEK,
+                UnicodeBlock.CYRILLIC,
+                UnicodeBlock.ARMENIAN,
+                UnicodeBlock.HEBREW,
+                UnicodeBlock.ARABIC,
+                UnicodeBlock.SYRIAC,
+                UnicodeBlock.THAANA,
+                UnicodeBlock.DEVANAGARI,
+                UnicodeBlock.BENGALI,
+                UnicodeBlock.GURMUKHI,
+                UnicodeBlock.GUJARATI,
+                UnicodeBlock.ORIYA,
+                UnicodeBlock.TAMIL,
+                UnicodeBlock.TELUGU,
+                UnicodeBlock.KANNADA,
+                UnicodeBlock.MALAYALAM,
+                UnicodeBlock.SINHALA,
+                UnicodeBlock.THAI,
+                UnicodeBlock.LAO,
+                UnicodeBlock.TIBETAN,
+                UnicodeBlock.MYANMAR,
+                UnicodeBlock.GEORGIAN,
+                UnicodeBlock.HANGUL_JAMO,
+                UnicodeBlock.ETHIOPIC,
+                UnicodeBlock.CHEROKEE,
+                UnicodeBlock.UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS,
+                UnicodeBlock.OGHAM,
+                UnicodeBlock.RUNIC,
+                UnicodeBlock.KHMER,
+                UnicodeBlock.MONGOLIAN,
+                UnicodeBlock.LATIN_EXTENDED_ADDITIONAL,
+                UnicodeBlock.GREEK_EXTENDED,
+                UnicodeBlock.GENERAL_PUNCTUATION,
+                UnicodeBlock.SUPERSCRIPTS_AND_SUBSCRIPTS,
+                UnicodeBlock.CURRENCY_SYMBOLS,
+                UnicodeBlock.COMBINING_MARKS_FOR_SYMBOLS,
+                UnicodeBlock.LETTERLIKE_SYMBOLS,
+                UnicodeBlock.NUMBER_FORMS,
+                UnicodeBlock.ARROWS,
+                UnicodeBlock.MATHEMATICAL_OPERATORS,
+                UnicodeBlock.MISCELLANEOUS_TECHNICAL,
+                UnicodeBlock.CONTROL_PICTURES,
+                UnicodeBlock.OPTICAL_CHARACTER_RECOGNITION,
+                UnicodeBlock.ENCLOSED_ALPHANUMERICS,
+                UnicodeBlock.BOX_DRAWING,
+                UnicodeBlock.BLOCK_ELEMENTS,
+                UnicodeBlock.GEOMETRIC_SHAPES,
+                UnicodeBlock.MISCELLANEOUS_SYMBOLS,
+                UnicodeBlock.DINGBATS,
+                UnicodeBlock.BRAILLE_PATTERNS,
+                UnicodeBlock.CJK_RADICALS_SUPPLEMENT,
+                UnicodeBlock.KANGXI_RADICALS,
+                UnicodeBlock.IDEOGRAPHIC_DESCRIPTION_CHARACTERS,
+                UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION,
+                UnicodeBlock.HIRAGANA,
+                UnicodeBlock.KATAKANA,
+                UnicodeBlock.BOPOMOFO,
+                UnicodeBlock.HANGUL_COMPATIBILITY_JAMO,
+                UnicodeBlock.KANBUN,
+                UnicodeBlock.BOPOMOFO_EXTENDED,
+                UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS,
+                UnicodeBlock.CJK_COMPATIBILITY,
+                UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A,
+                UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS,
+                UnicodeBlock.YI_SYLLABLES,
+                UnicodeBlock.YI_RADICALS,
+                UnicodeBlock.HANGUL_SYLLABLES,
+                UnicodeBlock.HIGH_SURROGATES,
+                UnicodeBlock.HIGH_PRIVATE_USE_SURROGATES,
+                UnicodeBlock.LOW_SURROGATES,
+                UnicodeBlock.PRIVATE_USE_AREA,
+                UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS,
+                UnicodeBlock.ALPHABETIC_PRESENTATION_FORMS,
+                UnicodeBlock.ARABIC_PRESENTATION_FORMS_A,
+                UnicodeBlock.COMBINING_HALF_MARKS,
+                UnicodeBlock.CJK_COMPATIBILITY_FORMS,
+                UnicodeBlock.SMALL_FORM_VARIANTS,
+                UnicodeBlock.ARABIC_PRESENTATION_FORMS_B,
+                UnicodeBlock.SPECIALS,
+                UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS,
+                UnicodeBlock.OLD_ITALIC,
+                UnicodeBlock.GOTHIC,
+                UnicodeBlock.DESERET,
+                UnicodeBlock.BYZANTINE_MUSICAL_SYMBOLS,
+                UnicodeBlock.MUSICAL_SYMBOLS,
+                UnicodeBlock.MATHEMATICAL_ALPHANUMERIC_SYMBOLS,
+                UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B,
+                UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT,
+                UnicodeBlock.TAGS,
+                UnicodeBlock.CYRILLIC_SUPPLEMENTARY,
+                UnicodeBlock.TAGALOG,
+                UnicodeBlock.HANUNOO,
+                UnicodeBlock.BUHID,
+                UnicodeBlock.TAGBANWA,
+                UnicodeBlock.MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A,
+                UnicodeBlock.SUPPLEMENTAL_ARROWS_A,
+                UnicodeBlock.SUPPLEMENTAL_ARROWS_B,
+                UnicodeBlock.MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B,
+                UnicodeBlock.SUPPLEMENTAL_MATHEMATICAL_OPERATORS,
+                UnicodeBlock.KATAKANA_PHONETIC_EXTENSIONS,
+                UnicodeBlock.VARIATION_SELECTORS,
+                UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_A,
+                UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B,
+                UnicodeBlock.LIMBU,
+                UnicodeBlock.TAI_LE,
+                UnicodeBlock.KHMER_SYMBOLS,
+                UnicodeBlock.PHONETIC_EXTENSIONS,
+                UnicodeBlock.MISCELLANEOUS_SYMBOLS_AND_ARROWS,
+                UnicodeBlock.YIJING_HEXAGRAM_SYMBOLS,
+                UnicodeBlock.LINEAR_B_SYLLABARY,
+                UnicodeBlock.LINEAR_B_IDEOGRAMS,
+                UnicodeBlock.AEGEAN_NUMBERS,
+                UnicodeBlock.UGARITIC,
+                UnicodeBlock.SHAVIAN,
+                UnicodeBlock.OSMANYA,
+                UnicodeBlock.CYPRIOT_SYLLABARY,
+                UnicodeBlock.TAI_XUAN_JING_SYMBOLS,
+                UnicodeBlock.VARIATION_SELECTORS_SUPPLEMENT
+        };
+        return result;
+    }
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/math/BigDecimal.java b/libcore/icu/src/main/java/com/ibm/icu4jni/math/BigDecimal.java
new file mode 100644
index 0000000..4460b19
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/math/BigDecimal.java
@@ -0,0 +1,34 @@
+package com.ibm.icu4jni.math;
+
+public class BigDecimal extends Number {
+
+    @Override
+    public double doubleValue() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public float floatValue() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public int intValue() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+
+    @Override
+    public long longValue() {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+    
+    @Override
+    public String toString() {
+        return "";
+    }
+
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/regex/NativeRegEx.java b/libcore/icu/src/main/java/com/ibm/icu4jni/regex/NativeRegEx.java
new file mode 100644
index 0000000..bdfff5b
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/regex/NativeRegEx.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.regex;
+
+public class NativeRegEx {
+
+    /**
+     * Opens (compiles) an ICU regular expression.
+     */
+    public static native int open(String pattern, int flags);
+    
+    /**
+     * Makes a copy of a compiled regular expression.
+     */
+    public static native int clone(int regex);
+    
+    /**
+     * Closes the regular expression, recovering all resources (memory) it was
+     * holding. 
+     */    
+    public static native void close(int regex);
+
+    /**
+     * Sets the subject text string upon which the regular expression will look
+     * for matches.
+     */
+    public static native void setText(int regex, String text);
+    
+    /**
+     * Attempts to match the input string, beginning at startIndex, against the
+     * pattern. 
+     */
+    public static native boolean matches(int regex, int startIndex);
+    
+    /**
+     * Attempts to match the input string, starting from the specified index,
+     * against the pattern. 
+     */
+    public static native boolean lookingAt(int regex, int startIndex);
+
+    /**
+     * Finds the first matching substring of the input string that matches the
+     * pattern. 
+     */
+    public static native boolean find(int regex, int startIndex);
+    
+    /**
+     * Finds the first matching substring of the input string that matches the
+     * pattern. 
+     */
+    public static native boolean findNext(int regex);
+    
+    /**
+     * Gets the number of capturing groups in this regular expression's pattern. 
+     */
+    public static native int groupCount(int regex);
+    
+    /**
+     * Gets all the group information for the current match of the pattern.
+     */
+    public static native void startEnd(int regex, int[] startEnd);
+    
+    /**
+     * Sets the region of the input to be considered during matching.
+     */
+    public static native void setRegion(int regex, int start, int end);
+    
+    /**
+     * Queries the start of the region of the input to be considered during
+     * matching.
+     */
+    public static native int regionStart(int regex);
+    
+    /**
+     * Queries the end of the region of the input to be considered during
+     * matching.
+     */
+    public static native int regionEnd(int regex);
+    
+    /**
+     * Controls the transparency of the region bounds.
+     */
+    public static native void useTransparentBounds(int regex, boolean value);
+    
+    /**
+     * Queries the transparency of the region bounds.
+     */
+    public static native boolean hasTransparentBounds(int regex);
+    
+    /**
+     * Controls the anchoring property of the region bounds.
+     */
+    public static native void useAnchoringBounds(int regex, boolean value);
+    
+    /**
+     * Queries the anchoring property of the region bounds.
+     */
+    public static native boolean hasAnchoringBounds(int regex);
+    
+    /**
+     * Queries whether we hit the end of the input during the last match.
+     */
+    public static native boolean hitEnd(int regex);
+    
+    /**
+     * Queries whether more input might change a current match, but wouldn't
+     * destroy it.
+     */
+    public static native boolean requireEnd(int regex);
+    
+    /**
+     * Resets the matcher, cause a current match to be lost, and sets the
+     * position at which a subsequent findNext() would start.
+     */
+    public static native void reset(int regex, int position);
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/BreakIterator.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/BreakIterator.java
new file mode 100644
index 0000000..c8f5372
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/BreakIterator.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.text;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.Locale;
+
+public abstract class BreakIterator implements Cloneable
+{
+    protected static int BI_CHAR_INSTANCE = 1;
+    protected static int BI_WORD_INSTANCE = 2;
+    protected static int BI_LINE_INSTANCE = 3;
+    protected static int BI_SENT_INSTANCE = 4;
+    
+    protected int type = 0;
+    
+    public static Locale[] getAvailableLocales() {
+        
+        String[] locales = NativeBreakIterator.getAvailableLocalesImpl();
+        
+        Locale[] result = new Locale[locales.length];
+        
+        String locale;
+        
+        int index, index2;
+        
+        for(int i = 0; i < locales.length; i++) {
+            locale = locales[i];
+            
+            index = locale.indexOf('_');
+            index2 = locale.lastIndexOf('_');
+            
+            if(index == -1) {
+                result[i] = new Locale(locales[i]);
+            } else if(index > 0 && index == index2) {
+                result[i] = new Locale(
+                        locale.substring(0,index),
+                        locale.substring(index+1));
+            } else if(index > 0 && index2 > index) {
+                result[i] = new Locale(
+                        locale.substring(0,index),
+                        locale.substring(index+1,index2),
+                        locale.substring(index2+1));
+            }
+        }
+        
+        return result;
+    }
+    
+    public static BreakIterator getCharacterInstance() {
+        int iter = NativeBreakIterator.getCharacterInstanceImpl("");
+        return new RuleBasedBreakIterator(iter, BI_CHAR_INSTANCE);
+    }
+
+    public static BreakIterator getCharacterInstance(Locale where) {
+        int iter = NativeBreakIterator.getCharacterInstanceImpl(where.toString());
+        return new RuleBasedBreakIterator(iter, BI_CHAR_INSTANCE);
+    }
+
+    public static BreakIterator getLineInstance() {
+        int iter = NativeBreakIterator.getLineInstanceImpl("");
+        return new RuleBasedBreakIterator(iter, BI_LINE_INSTANCE);
+    }
+    
+    public static BreakIterator getLineInstance(Locale where) {
+        int iter = NativeBreakIterator.getLineInstanceImpl(where.toString());
+        return new RuleBasedBreakIterator(iter, BI_LINE_INSTANCE);
+    }
+    
+    public static BreakIterator getSentenceInstance() {
+        int iter = NativeBreakIterator.getSentenceInstanceImpl("");
+        return new RuleBasedBreakIterator(iter, BI_SENT_INSTANCE);
+    }
+
+    public static BreakIterator getSentenceInstance(Locale where) {
+        int iter = NativeBreakIterator.getSentenceInstanceImpl(where.toString());
+        return new RuleBasedBreakIterator(iter, BI_SENT_INSTANCE);
+    }
+    
+    public static BreakIterator getWordInstance() {
+        int iter = NativeBreakIterator.getWordInstanceImpl("");
+        return new RuleBasedBreakIterator(iter, BI_WORD_INSTANCE);
+    }
+
+    public static BreakIterator getWordInstance(Locale where) {
+        int iter = NativeBreakIterator.getWordInstanceImpl(where.toString());
+        return new RuleBasedBreakIterator(iter, BI_WORD_INSTANCE);
+    }
+
+    public void setText(String newText) {
+        setText(new StringCharacterIterator(newText));
+    }
+
+    public abstract boolean isBoundary(int offset);
+
+    public abstract int preceding(int offset);
+    
+    public abstract Object clone();
+
+    public abstract int current();
+
+    public abstract int first();
+
+    public abstract int following(int offset);
+
+    public abstract CharacterIterator getText();
+
+    public abstract int last();
+
+    public abstract int next(int n);
+
+    public abstract int next();
+
+    public abstract int previous();
+
+    public abstract void setText(CharacterIterator newText);
+
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/CollationAttribute.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/CollationAttribute.java
new file mode 100644
index 0000000..b1c6107
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/CollationAttribute.java
@@ -0,0 +1,214 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+/**
+* Interface for storing ICU collation equivalent enum values.
+* Constants with the prefix VALUE corresponds to ICU's UColAttributeValues,
+* the rest corresponds to UColAttribute.
+* @author syn wee quek
+* @stable ICU 2.4
+*/
+
+public final class CollationAttribute
+{ 
+  // Collation strength constants ----------------------------------
+  /**
+  * Default value, accepted by most attributes
+  * @stable ICU 2.4
+  */ 
+  public static final int VALUE_DEFAULT = -1;
+  /** 
+  * Primary collation strength 
+  * @stable ICU 2.4
+  */
+  public static final int VALUE_PRIMARY = 0;
+  /** 
+  * Secondary collation strength 
+  * @stable ICU 2.4
+  */
+  public static final int VALUE_SECONDARY = 1;
+  /** 
+  * Tertiary collation strength 
+  * @stable ICU 2.4
+  */
+  public static final int VALUE_TERTIARY = 2;
+  /** 
+  * Default collation strength 
+  * @stable ICU 2.4
+  */
+  public static final int VALUE_DEFAULT_STRENGTH = VALUE_TERTIARY;
+  /** 
+  * Quaternary collation strength 
+  * @stable ICU 2.4
+  */
+  public static final int VALUE_QUATERNARY = 3;
+  /** 
+  * Identical collation strength 
+  * @stable ICU 2.4
+  */
+  public static final int VALUE_IDENTICAL = 15;
+
+  /** 
+   * Turn the feature off - works for FRENCH_COLLATION, CASE_LEVEL, 
+   * HIRAGANA_QUATERNARY_MODE and DECOMPOSITION_MODE
+   * @stable ICU 2.4
+   */
+  public static final int VALUE_OFF = 16;
+  /** @stable ICU 2.4 */
+  public static final int VALUE_ON = 17;
+  
+  /** 
+   * ALTERNATE_HANDLING mode constants
+   * @stable ICU 2.4
+   */
+  public static final int VALUE_SHIFTED = 20;
+  /** @stable ICU 2.4 */
+  public static final int VALUE_NON_IGNORABLE = 21;
+
+  /** 
+   * CASE_FIRST mode constants
+   * @stable ICU 2.4
+   */
+  public static final int VALUE_LOWER_FIRST = 24;
+  /** @stable ICU 2.4 */
+  public static final int VALUE_UPPER_FIRST = 25;
+
+  /** 
+   * NORMALIZATION_MODE mode constants
+   * @deprecated ICU 2.4. Users advised to use VALUE_ON instead.
+   */
+  public static final int VALUE_ON_WITHOUT_HANGUL = 28;
+
+  /** 
+   * Number of attribute value constants
+   * @stable ICU 2.4
+   */
+  public static final int VALUE_ATTRIBUTE_VALUE_COUNT = 29;
+
+  // Collation attribute constants -----------------------------------
+  
+  /** 
+   * Attribute for direction of secondary weights
+   * @stable ICU 2.4
+   */
+  public static final int FRENCH_COLLATION = 0;
+  /** 
+   * Attribute for handling variable elements
+   * @stable ICU 2.4
+   */
+  public static final int ALTERNATE_HANDLING = 1;
+  /** 
+   * Who goes first, lower case or uppercase.
+   * @stable ICU 2.4
+   */
+  public static final int CASE_FIRST = 2;
+  /** 
+   * Do we have an extra case level
+   * @stable ICU 2.4
+   */
+  public static final int CASE_LEVEL = 3;
+  /** 
+   * Attribute for normalization
+   * @stable ICU 2.4
+   */
+  public static final int NORMALIZATION_MODE = 4; 
+  /** 
+   * Attribute for strength 
+   * @stable ICU 2.4
+   */
+  public static final int STRENGTH = 5;
+  /** 
+   * Attribute count
+   * @stable ICU 2.4
+   */
+  public static final int ATTRIBUTE_COUNT = 6;
+  
+  // package methods --------------------------------------------------
+  
+  /**
+  * Checks if argument is a valid collation strength
+  * @param strength potential collation strength
+  * @return true if strength is a valid collation strength, false otherwise
+  */
+  static boolean checkStrength(int strength)
+  {
+    if (strength < VALUE_PRIMARY || 
+        (strength > VALUE_QUATERNARY && strength != VALUE_IDENTICAL))
+      return false;
+    return true;
+  }
+  
+  /**
+  * Checks if argument is a valid collation type
+  * @param type collation type to be checked
+  * @return true if type is a valid collation type, false otherwise
+  */
+  static boolean checkType(int type)
+  {
+    if (type < FRENCH_COLLATION || type > STRENGTH)
+      return false;
+    return true;
+  }
+
+  /**
+  * Checks if argument is a valid normalization type
+  * @param type normalization type to be checked
+  * @return true if type is a valid normalization type, false otherwise
+  */
+  static boolean checkNormalization(int type)
+  {
+    if (type != VALUE_ON && type != VALUE_OFF 
+        && type != VALUE_ON_WITHOUT_HANGUL) {
+        return false;
+    }
+    return true;
+  }
+  
+  /**
+  * Checks if attribute type and corresponding attribute value is valid
+  * @param type attribute type
+  * @param value attribute value
+  * @return true if the pair is valid, false otherwise
+  */
+  static boolean checkAttribute(int type, int value)
+  {
+    if (value == VALUE_DEFAULT) {
+      return true;
+    }
+      
+    switch (type)
+    {
+      case FRENCH_COLLATION :
+                          if (value >= VALUE_OFF && value <= VALUE_ON)
+                            return true;
+                          break;
+      case ALTERNATE_HANDLING :
+                          if (value >= VALUE_SHIFTED && 
+                              value <= VALUE_NON_IGNORABLE)
+                            return true;
+                          break;
+      case CASE_FIRST :
+                          if (value >= VALUE_LOWER_FIRST && 
+                              value <= VALUE_UPPER_FIRST)
+                            return true;
+                          break;
+      case CASE_LEVEL :
+                          return (value == VALUE_ON || 
+                                  value <= VALUE_OFF);
+      case NORMALIZATION_MODE : 
+                          return (value == VALUE_OFF || value == VALUE_ON ||
+                                  value == VALUE_ON_WITHOUT_HANGUL);
+      case STRENGTH :
+                          checkStrength(value);
+    }
+    return false;
+  }
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/CollationElementIterator.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/CollationElementIterator.java
new file mode 100644
index 0000000..0f5bae4
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/CollationElementIterator.java
@@ -0,0 +1,230 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+import java.text.CharacterIterator;
+
+
+/**
+* Collation element iterator JNI wrapper.
+* Iterates over the collation elements of a data string.
+* The iterator supports both forward and backwards full iteration, ie if 
+* backwards iteration is performed in the midst of a forward iteration, the 
+* result is undefined. 
+* To perform a backwards iteration in the midst of a forward iteration, 
+* reset() has to be called. 
+* This will shift the position to either the start or the last character in the 
+* data string depending on whether next() is called or previous().
+* <pre>
+*   RuleBasedCollator coll = Collator.getInstance();
+*   CollationElementIterator iterator = coll.getCollationElementIterator("abc");
+*   int ce = 0;
+*   while (ce != CollationElementIterator.NULLORDER) {
+*     ce = iterator.next();
+*   }
+*   iterator.reset();
+*   while (ce != CollationElementIterator.NULLORDER) {
+*     ce = iterator.previous();
+*   }
+* </pre>
+* @author syn wee quek
+* @stable ICU 2.4
+*/
+    
+public final class CollationElementIterator
+{
+  // public data member -------------------------------------------
+  
+  /**
+   * @stable ICU 2.4
+   */
+  public static final int NULLORDER = 0xFFFFFFFF;
+  
+  // public methods -----------------------------------------------
+  
+  /**
+  * Reset the collation elements to their initial state.
+  * This will move the 'cursor' to the beginning of the text.
+  * @stable ICU 2.4
+  */
+  public void reset()
+  {
+    NativeCollation.reset(m_collelemiterator_);
+  }
+
+  /**
+  * Get the ordering priority of the next collation element in the text.
+  * A single character may contain more than one collation element.
+  * @return next collation elements ordering, or NULLORDER if the end of the 
+  *         text is reached.
+  * @stable ICU 2.4
+  */
+  public int next()
+  {
+    return NativeCollation.next(m_collelemiterator_);
+  }
+
+  /**
+  * Get the ordering priority of the previous collation element in the text.
+  * A single character may contain more than one collation element.
+  * @return previous collation element ordering, or NULLORDER if the end of 
+  *         the text is reached.
+  * @stable ICU 2.4
+  */
+  public int previous()
+  {
+    return NativeCollation.previous(m_collelemiterator_);
+  }
+
+  /**
+  * Get the maximum length of any expansion sequences that end with the 
+  * specified comparison order.
+  * @param order collation order returned by previous or next.
+  * @return maximum size of the expansion sequences ending with the collation 
+  *              element or 1 if collation element does not occur at the end of 
+  *              any expansion sequence
+  * @stable ICU 2.4
+  */
+  public int getMaxExpansion(int order)
+  {
+    return NativeCollation.getMaxExpansion(m_collelemiterator_, order);
+  }
+
+  /**
+  * Set the text containing the collation elements.
+  * @param source text containing the collation elements.
+  * @stable ICU 2.4
+  */
+  public void setText(String source)
+  {
+    NativeCollation.setText(m_collelemiterator_, source);
+  }
+
+  // BEGIN android-added
+  public void setText(CharacterIterator source)
+  {
+    NativeCollation.setText(m_collelemiterator_, source.toString());
+  }
+  // END android-added
+
+  /**
+  * Get the offset of the current source character.
+  * This is an offset into the text of the character containing the current
+  * collation elements.
+  * @return offset of the current source character.
+  * @stable ICU 2.4
+  */
+  public int getOffset()
+  {
+    return NativeCollation.getOffset(m_collelemiterator_);
+  }
+
+  /**
+  * Set the offset of the current source character.
+  * This is an offset into the text of the character to be processed.
+  * @param offset The desired character offset.
+  * @stable ICU 2.4
+  */
+  public void setOffset(int offset)
+  {
+    NativeCollation.setOffset(m_collelemiterator_, offset);
+  }
+  
+  /**
+  * Gets the primary order of a collation order.
+  * @param order the collation order
+  * @return the primary order of a collation order.
+  * @stable ICU 2.4
+  */
+  public static int primaryOrder(int order) 
+  {
+    return ((order & PRIMARY_ORDER_MASK_) >> PRIMARY_ORDER_SHIFT_) &
+                                                       UNSIGNED_16_BIT_MASK_;
+  }
+
+  /**
+  * Gets the secondary order of a collation order.
+  * @param order the collation order
+  * @return the secondary order of a collation order.
+  * @stable ICU 2.4
+  */
+  public static int secondaryOrder(int order)
+  {
+    return (order & SECONDARY_ORDER_MASK_) >> SECONDARY_ORDER_SHIFT_;
+  }
+
+  /**
+  * Gets the tertiary order of a collation order.
+  * @param order the collation order
+  * @return the tertiary order of a collation order.
+  * @stable ICU 2.4
+  */
+  public static int tertiaryOrder(int order)
+  {
+    return order & TERTIARY_ORDER_MASK_;
+  }
+  
+  // protected constructor ----------------------------------------
+  
+  /**
+  * CollationElementIteratorJNI constructor. 
+  * The only caller of this class should be 
+  * RuleBasedCollator.getCollationElementIterator(). 
+  * @param collelemiteratoraddress address of C collationelementiterator
+  */
+  CollationElementIterator(int collelemiteratoraddress)
+  {
+    m_collelemiterator_ = collelemiteratoraddress;
+  }
+
+  // protected methods --------------------------------------------
+  
+  /**
+  * Garbage collection.
+  * Close C collator and reclaim memory.
+  * @stable ICU 2.4
+  */
+  protected void finalize()
+  {
+    NativeCollation.closeElements(m_collelemiterator_);
+  }
+  
+  // private data members -----------------------------------------
+ 
+  /**
+  * C collator
+  */
+  private int m_collelemiterator_;
+  
+  /** 
+  * ICU constant primary order mask for collation elements 
+  */
+  private static final int PRIMARY_ORDER_MASK_ = 0xffff0000;
+  /** 
+  * ICU constant secondary order mask for collation elements 
+  */
+  private static final int SECONDARY_ORDER_MASK_ = 0x0000ff00;
+  /** 
+  * ICU constant tertiary order mask for collation elements 
+  */
+  private static final int TERTIARY_ORDER_MASK_ = 0x000000ff;
+  /** 
+  * ICU constant primary order shift for collation elements 
+  */
+  private static final int PRIMARY_ORDER_SHIFT_ = 16;
+  /** 
+  * ICU constant secondary order shift for collation elements 
+  */
+  private static final int SECONDARY_ORDER_SHIFT_ = 8;
+  /**
+  * Unsigned 16 bit mask
+  */
+  private static final int UNSIGNED_16_BIT_MASK_ = 0x0000FFFF;
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/CollationKey.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/CollationKey.java
new file mode 100644
index 0000000..7e8a000
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/CollationKey.java
@@ -0,0 +1,186 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+/**
+* Collation key wrapper, containing the byte array sort key.
+* @author syn wee quek
+* @stable ICU 2.4
+*/
+
+public final class CollationKey implements Comparable
+{ 
+  // public methods -----------------------------------------------
+
+  /**
+  * Bitwise comparison for the collation keys
+  * @param target CollationKey to be compared
+  * @return comparison result from Collator, RESULT_LESS, RESULT_EQUAL, 
+  *         RESULT_GREATER
+  * @stable ICU 2.4    
+  */
+  public int compareTo(CollationKey target)
+  {
+    byte tgtbytes[] = target.m_bytes_;
+    
+    if (m_bytes_ == null || m_bytes_.length == 0) {
+      if (tgtbytes == null || tgtbytes.length == 0) {
+        return Collator.RESULT_EQUAL;
+      }
+      return Collator.RESULT_LESS;
+    }
+    else {
+      if (tgtbytes == null || tgtbytes.length == 0) {
+        return Collator.RESULT_GREATER;
+      }
+    }
+        
+    int count = m_bytes_.length;
+    if (tgtbytes.length < count) {
+      count = tgtbytes.length;
+    }
+
+    int s,
+        t;
+    for (int i = 0; i < count; i ++)
+    {
+      // unable to use Arrays.equals
+      s = m_bytes_[i] & UNSIGNED_BYTE_MASK_;
+      t = tgtbytes[i] & UNSIGNED_BYTE_MASK_;
+      if (s < t) {
+        return Collator.RESULT_LESS;
+      }
+      if (s > t) {
+        return Collator.RESULT_GREATER;
+      }
+    }
+
+    if (m_bytes_.length < target.m_bytes_.length) {
+      return Collator.RESULT_LESS;
+    }
+    
+    if (m_bytes_.length > target.m_bytes_.length) {
+      return Collator.RESULT_GREATER;
+    }
+    
+    return Collator.RESULT_EQUAL;
+  }
+  
+  /**
+  * Bitwise comparison for the collation keys.
+  * Argument is casted to CollationKey
+  * @param target CollationKey to be compared
+  * @return comparison result from Collator, RESULT_LESS, RESULT_EQUAL, 
+  * RESULT_GREATER
+  * @stable ICU 2.4
+  */
+  public int compareTo(Object target)
+  {
+    return compareTo((CollationKey)target);
+  }
+
+  /**
+  * Checks if target object is equal to this object.
+  * Target is first casted to CollationKey and bitwise compared.
+  * @param target comparison object
+  * @return true if both objects are equal, false otherwise
+  * @stable ICU 2.4
+  */
+  public boolean equals(Object target)
+  {
+    if (this == target) {
+      return true;
+    }
+      
+    // checks getClass here since CollationKey is final not subclassable
+    if (target == null || target.getClass() != getClass()) {
+      return false;
+    }
+    
+    return compareTo((CollationKey)target) == Collator.RESULT_EQUAL;
+  }
+
+  /**
+  * Creates a hash code for this CollationKey. 
+  * Compute the hash by iterating sparsely over about 32 (up to 63) bytes 
+  * spaced evenly through the string.  For each byte, multiply the previous 
+  * hash value by a prime number and add the new byte in, like a linear 
+  * congruential random number generator, producing a pseudorandom 
+  * deterministic value well distributed over the output range.
+  * @return hash value of collation key. Hash value is never 0.
+  * @stable ICU 2.4
+  */
+  public int hashCode()
+  {
+    if (m_hash_ == 0)
+    {
+      if (m_bytes_ != null || m_bytes_.length != 0) 
+      {                        
+        int len = m_bytes_.length;
+        int inc = ((len - 32) / 32) + 1;  
+        for (int i = 0; i < len;)
+        {
+          m_hash_ = (m_hash_ * 37) + m_bytes_[i];
+          i += inc;                         
+        }                                     
+      }             
+      if (m_hash_ == 0)
+        m_hash_ = 1;
+    }
+    return m_hash_;
+  }
+
+  /**
+  * Create the value of the Collation key in term of bytes
+  * @return value of Collation key in bytes
+  * @stable ICU 2.4
+  */
+  public byte[] toByteArray()
+  {
+    if (m_bytes_ == null || m_bytes_.length == 0)
+      return null;
+      
+    return (byte[])m_bytes_.clone(); 
+  }
+
+  // package constructors ----------------------------------------------
+  
+  /**
+  * Default constructor, for use by the Collator and its subclasses.
+  */
+  CollationKey()
+  {
+    m_hash_ = 0;
+  }
+  
+  /**
+  * Constructor, for use only by the Collator and its subclasses.
+  */
+  CollationKey(byte[] bytes)
+  {
+    m_bytes_ = bytes;
+    m_hash_ = 0;
+  }
+
+  // private data members -----------------------------------------------
+  
+  private byte m_bytes_[];
+  
+  /**
+  * Mask value to retrieve a single unsigned byte
+  */
+  private static final int UNSIGNED_BYTE_MASK_ = 0x00FF;
+  
+  /**
+  * Cached hash value
+  */
+  private int m_hash_;
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/Collator.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/Collator.java
new file mode 100644
index 0000000..483457d
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/Collator.java
@@ -0,0 +1,431 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+import java.util.Locale;
+import com.ibm.icu4jni.text.RuleBasedCollator;
+
+/**
+* Abstract class handling locale specific collation via JNI and ICU.
+* Subclasses implement specific collation strategies. One subclass, 
+* com.ibm.icu4jni.text.RuleBasedCollator, is currently provided and is 
+* applicable to a wide set of languages. Other subclasses may be created to 
+* handle more specialized needs. 
+* You can use the static factory method, getInstance(), to obtain the 
+* appropriate Collator object for a given locale. 
+* 
+* <pre>
+* // Compare two strings in the default locale
+* Collator myCollator = Collator.getInstance();
+* if (myCollator.compare("abc", "ABC") < 0) {
+*   System.out.println("abc is less than ABC");
+* }
+* else {
+*   System.out.println("abc is greater than or equal to ABC");
+* }
+* </pre>
+*
+* You can set a Collator's strength property to determine the level of 
+* difference considered significant in comparisons. 
+* Five strengths in CollationAttribute are provided: VALUE_PRIMARY, 
+* VALUE_SECONDARY, VALUE_TERTIARY, VALUE_QUARTENARY and VALUE_IDENTICAL. 
+* The exact assignment of strengths to language features is locale dependant. 
+* For example, in Czech, "e" and "f" are considered primary differences, while 
+* "e" and "?" latin small letter e with circumflex are secondary differences, 
+* "e" and "E" are tertiary differences and "e" and "e" are identical. 
+*
+* <p>
+* The following shows how both case and accents could be ignored for US 
+* English. 
+* <pre>
+* //Get the Collator for US English and set its strength to PRIMARY
+* Collator usCollator = Collator.getInstance(Locale.US);
+* usCollator.setStrength(Collator.PRIMARY);
+* if (usCollator.compare("abc", "ABC") == 0) {
+*   System.out.println("Strings are equivalent");
+* }
+* </pre>
+* For comparing Strings exactly once, the compare method provides the best 
+* performance. 
+* When sorting a list of Strings however, it is generally necessary to compare 
+* each String multiple times. 
+* In this case, com.ibm.icu4jni.text.CollationKey provide better performance. 
+* The CollationKey class converts a String to a series of bits that can be 
+* compared bitwise against other CollationKeys. 
+* A CollationKey is created by a Collator object for a given String. 
+* Note: CollationKeys from different Collators can not be compared. 
+* </p>
+*
+* Considerations :
+* 1) ErrorCode not returned to user throw exceptions instead
+* 2) Similar API to java.text.Collator
+* @author syn wee quek
+* @stable ICU 2.4
+*/
+
+public abstract class Collator implements Cloneable
+{ 
+    // public data members ---------------------------------------------------
+        
+    /**
+     * Strongest collator strength value. Typically used to denote differences 
+     * between base characters. See class documentation for more explanation.
+     * @see #setStrength
+     * @see #getStrength
+     * @stable ICU 2.4
+     */
+    public final static int PRIMARY = CollationAttribute.VALUE_PRIMARY;
+
+    /**
+     * Second level collator strength value. 
+     * Accents in the characters are considered secondary differences.
+     * Other differences between letters can also be considered secondary 
+     * differences, depending on the language. 
+     * See class documentation for more explanation.
+     * @see #setStrength
+     * @see #getStrength
+     * @stable ICU 2.4
+     */
+    public final static int SECONDARY = CollationAttribute.VALUE_SECONDARY;
+
+    /**
+     * Third level collator strength value. 
+     * Upper and lower case differences in characters are distinguished at this
+     * strength level. In addition, a variant of a letter differs from the base 
+     * form on the tertiary level.
+     * See class documentation for more explanation.
+     * @see #setStrength
+     * @see #getStrength
+     * @stable ICU 2.4
+     */
+    public final static int TERTIARY = CollationAttribute.VALUE_TERTIARY;                            
+
+    /**
+     * Fourth level collator strength value. 
+     * When punctuation is ignored 
+     * <a href="http://www-124.ibm.com/icu/userguide/Collate_Concepts.html#Ignoring_Punctuation">
+     * (see Ignoring Punctuations in the user guide)</a> at PRIMARY to TERTIARY 
+     * strength, an additional strength level can 
+     * be used to distinguish words with and without punctuation.
+     * See class documentation for more explanation.
+     * @see #setStrength
+     * @see #getStrength
+     * @stable ICU 2.4
+     */
+    public final static int QUATERNARY = CollationAttribute.VALUE_QUATERNARY;
+
+    /**
+     * <p>
+     * Smallest Collator strength value. When all other strengths are equal, 
+     * the IDENTICAL strength is used as a tiebreaker. The Unicode code point 
+     * values of the NFD form of each string are compared, just in case there 
+     * is no difference. 
+     * See class documentation for more explanation.
+     * </p>
+     * <p>
+     * Note this value is different from JDK's
+     * </p>
+     * @stable ICU 2.4
+     */
+    public final static int IDENTICAL = CollationAttribute.VALUE_IDENTICAL;
+
+    /**
+     * <p>Decomposition mode value. With NO_DECOMPOSITION set, Strings
+     * will not be decomposed for collation. This is the default
+     * decomposition setting unless otherwise specified by the locale
+     * used to create the Collator.</p>
+     *
+     * <p><strong>Note</strong> this value is different from the JDK's.</p>
+     * @see #CANONICAL_DECOMPOSITION
+     * @see #getDecomposition
+     * @see #setDecomposition
+     * @stable ICU 2.4 
+     */
+    public final static int NO_DECOMPOSITION = CollationAttribute.VALUE_OFF;
+
+    /**
+     * <p>Decomposition mode value. With CANONICAL_DECOMPOSITION set,
+     * characters that are canonical variants according to the Unicode standard
+     * will be decomposed for collation.</p>
+     *
+     * <p>CANONICAL_DECOMPOSITION corresponds to Normalization Form D as
+     * described in <a href="http://www.unicode.org/unicode/reports/tr15/">
+     * Unicode Technical Report #15</a>.
+     * </p>
+     * @see #NO_DECOMPOSITION
+     * @see #getDecomposition
+     * @see #setDecomposition
+     * @stable ICU 2.4 
+     */
+    public final static int CANONICAL_DECOMPOSITION 
+                                                = CollationAttribute.VALUE_ON;
+  
+    // Collation result constants -----------------------------------
+    // corresponds to ICU's UCollationResult enum balues
+    /** 
+     * string a == string b 
+     * @stable ICU 2.4
+     */
+    public static final int RESULT_EQUAL = 0;
+    /** 
+     * string a > string b 
+     * @stable ICU 2.4
+     */
+    public static final int RESULT_GREATER = 1;
+    /** 
+     * string a < string b 
+     * @stable ICU 2.4
+     */
+    public static final int RESULT_LESS = -1;
+    /** 
+     * accepted by most attributes 
+     * @stable ICU 2.4
+     */
+    public static final int RESULT_DEFAULT = -1;
+  
+    // public methods -----------------------------------------------
+  
+  /**
+  * Factory method to create an appropriate Collator which uses the default
+  * locale collation rules.
+  * Current implementation createInstance() returns a RuleBasedCollator(Locale) 
+  * instance. The RuleBasedCollator will be created in the following order,
+  * <ul>
+  * <li> Data from argument locale resource bundle if found, otherwise
+  * <li> Data from parent locale resource bundle of arguemtn locale if found,
+  *      otherwise
+  * <li> Data from built-in default collation rules if found, other
+  * <li> null is returned
+  * </ul>
+  * @return an instance of Collator
+  * @stable ICU 2.4
+  */
+  public static Collator getInstance()
+  {
+    return getInstance(null);
+  }
+
+  /**
+  * Factory method to create an appropriate Collator which uses the argument
+  * locale collation rules.<br>
+  * Current implementation createInstance() returns a RuleBasedCollator(Locale) 
+  * instance. The RuleBasedCollator will be created in the following order,
+  * <ul>
+  * <li> Data from argument locale resource bundle if found, otherwise
+  * <li> Data from parent locale resource bundle of arguemtn locale if found,
+  *      otherwise
+  * <li> Data from built-in default collation rules if found, other
+  * <li> null is returned
+  * </ul>
+  * @param locale to be used for collation
+  * @return an instance of Collator
+  * @stable ICU 2.4
+  */
+  public static Collator getInstance(Locale locale)
+  {
+    RuleBasedCollator result = new RuleBasedCollator(locale);
+    return result;
+  }
+
+  /**
+  * Locale dependent equality check for the argument strings.
+  * @param source string
+  * @param target string
+  * @return true if source is equivalent to target, false otherwise 
+  * @stable ICU 2.4
+  */
+  public boolean equals(String source, String target)
+  {
+    return (compare(source, target) == RESULT_EQUAL);
+  }
+  
+  /**
+  * Checks if argument object is equals to this object.
+  * @param target object
+  * @return true if source is equivalent to target, false otherwise 
+  * @stable ICU 2.4
+  */
+  public abstract boolean equals(Object target);
+  
+  /**
+  * Makes a copy of the current object.
+  * @return a copy of this object
+  * @stable ICU 2.4
+  */
+  public abstract Object clone() throws CloneNotSupportedException;
+  
+  /**
+  * The comparison function compares the character data stored in two
+  * different strings. Returns information about whether a string is less 
+  * than, greater than or equal to another string.
+  * <p>Example of use:
+  * <pre>
+  * .  Collator myCollation = Collator.getInstance(Locale::US);
+  * .  myCollation.setStrength(CollationAttribute.VALUE_PRIMARY);
+  * .  // result would be CollationAttribute.VALUE_EQUAL 
+  * .  // ("abc" == "ABC")
+  * .  // (no primary difference between "abc" and "ABC")
+  * .  int result = myCollation.compare("abc", "ABC",3);
+  * .  myCollation.setStrength(CollationAttribute.VALUE_TERTIARY);
+  * .  // result would be Collation.LESS (abc" &lt;&lt;&lt; "ABC")
+  * .  // (with tertiary difference between "abc" and "ABC")
+  * .  int result = myCollation.compare("abc", "ABC",3);
+  * </pre>
+  * @param source source string.
+  * @param target target string.
+  * @return result of the comparison, Collator.RESULT_EQUAL, 
+  *         Collator.RESULT_GREATER or Collator.RESULT_LESS
+  * @stable ICU 2.4
+  */
+  public abstract int compare(String source, String target);
+                                               
+    /**
+     * Get the decomposition mode of this Collator. 
+     * @return the decomposition mode
+     * @see #CANONICAL_DECOMPOSITION
+     * @see #NO_DECOMPOSITION
+     * @stable ICU 2.4
+     */
+    public abstract int getDecomposition();
+
+    /**
+     * Set the normalization mode used int this object
+     * The normalization mode influences how strings are compared.
+     * @param mode desired normalization mode
+     * @see #CANONICAL_DECOMPOSITION
+     * @see #NO_DECOMPOSITION
+     * @stable ICU 2.4
+     */
+    public abstract void setDecomposition(int mode);
+
+    /**
+     * Determines the minimum strength that will be use in comparison or
+     * transformation.
+     * <p>
+     * E.g. with strength == SECONDARY, the tertiary difference is ignored
+     * </p>
+     * <p>
+     * E.g. with strength == PRIMARY, the secondary and tertiary difference 
+     * are ignored.
+     * </p>
+     * @return the current comparison level.
+     * @see #PRIMARY
+     * @see #SECONDARY
+     * @see #TERTIARY
+     * @see #QUATERNARY
+     * @see #IDENTICAL
+     * @stable ICU 2.4
+     */
+    public abstract int getStrength();
+  
+  /**
+  * Gets the attribute to be used in comparison or transformation.
+  * @param type the attribute to be set from CollationAttribute
+  * @return value attribute value from CollationAttribute
+  * @stable ICU 2.4
+  */
+  public abstract int getAttribute(int type);
+  
+    /**
+     * Sets the minimum strength to be used in comparison or transformation.
+     * <p>Example of use:
+     * <pre>
+     * . Collator myCollation = Collator.createInstance(Locale::US);
+     * . myCollation.setStrength(PRIMARY);
+     * . // result will be "abc" == "ABC"
+     * . // tertiary differences will be ignored
+     * . int result = myCollation->compare("abc", "ABC"); 
+     * </pre>
+     * @param strength the new comparison level.
+     * @see #PRIMARY
+     * @see #SECONDARY
+     * @see #TERTIARY
+     * @see #QUATERNARY 
+     * @see #IDENTICAL
+     * @stable ICU 2.4
+     */
+     public abstract void setStrength(int strength);
+  
+  /**
+  * Sets the attribute to be used in comparison or transformation.
+  * <p>Example of use:
+  * <pre>
+  * . Collator myCollation = Collator.createInstance(Locale::US);
+  * . myCollation.setAttribute(CollationAttribute.CASE_LEVEL, 
+  * .                          CollationAttribute.VALUE_ON);
+  * . int result = myCollation->compare("\\u30C3\\u30CF", 
+  * .                                   "\\u30C4\\u30CF");
+  * . // result will be Collator.RESULT_LESS.
+  * </pre>
+  * @param type the attribute to be set from CollationAttribute
+  * @param value attribute value from CollationAttribute
+  * @stable ICU 2.4
+  */
+  public abstract void setAttribute(int type, int value);
+  
+  /**
+  * Get the sort key as an CollationKey object from the argument string.
+  * To retrieve sort key in terms of byte arrays, use the method as below<br>
+  * <code>
+  * Collator collator = Collator.getInstance();
+  * CollationKey collationkey = collator.getCollationKey("string");
+  * byte[] array = collationkey.toByteArray();
+  * </code><br>
+  * Byte array result are zero-terminated and can be compared using 
+  * java.util.Arrays.equals();
+  * @param source string to be processed.
+  * @return the sort key
+  * @stable ICU 2.4
+  */
+  public abstract CollationKey getCollationKey(String source);
+  
+  /**
+  * Returns a hash of this collation object
+  * @return hash of this collation object
+  * @stable ICU 2.4
+  */
+  public abstract int hashCode();
+  
+  // BEGIN android-added
+  public static Locale[] getAvailableLocales() {
+      
+      String[] locales = NativeCollation.getAvailableLocalesImpl();
+      
+      Locale[] result = new Locale[locales.length];
+      
+      String locale;
+      
+      int index, index2;
+      
+      for(int i = 0; i < locales.length; i++) {
+          locale = locales[i];
+          
+          index = locale.indexOf('_');
+          index2 = locale.lastIndexOf('_');
+          
+          if(index == -1) {
+              result[i] = new Locale(locales[i]);
+          } else if(index == 2 && index == index2) {
+              result[i] = new Locale(
+                      locale.substring(0,2),
+                      locale.substring(3,5));
+          } else if(index == 2 && index2 == 5) {
+              result[i] = new Locale(
+                      locale.substring(0,2),
+                      locale.substring(3,5),
+                      locale.substring(6));
+          }
+      }
+      
+      return result;
+  }
+  // END android-added
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java
new file mode 100644
index 0000000..4dbc7e3
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.text;
+
+import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatAttribute;
+import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatTextAttribute;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Currency;
+import java.util.Locale;
+
+public class DecimalFormat extends NumberFormat {
+    
+    private int addr;
+    
+    private DecimalFormatSymbols symbols;
+    
+    // fix to be icu4j conform (harmony wants this field to exist) 
+    // for serialization of java.text.DecimalFormat
+    @SuppressWarnings("unused")
+    private boolean useExponentialNotation = false;
+    @SuppressWarnings("unused")
+    private byte minExponentDigits = 0;
+    
+    public DecimalFormat(String pattern, DecimalFormatSymbols icuSymbols) {
+        this.addr = icuSymbols.getAddr();
+        this.symbols = icuSymbols;
+        applyPattern(pattern);
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode() * 37 + this.getPositivePrefix().hashCode();
+    }
+    
+    @Override
+    public Object clone() {
+        String pat = this.toPattern();
+        Locale loc = this.symbols.getLocale();
+        DecimalFormatSymbols sym = (DecimalFormatSymbols) this.symbols.clone();
+        DecimalFormat newdf = new DecimalFormat(pat, sym);
+        newdf.setMaximumIntegerDigits(this.getMaximumIntegerDigits());
+        newdf.setMaximumFractionDigits(this.getMaximumFractionDigits());
+        newdf.setMinimumIntegerDigits(this.getMinimumIntegerDigits());
+        newdf.setMinimumFractionDigits(this.getMinimumFractionDigits());
+        newdf.setGroupingUsed(this.isGroupingUsed());
+        newdf.setGroupingSize(this.getGroupingSize());
+        return newdf;
+    }
+    
+    @Override
+    public boolean equals(Object object) {
+        if (object == this) {
+            return true;
+        }
+        if (!(object instanceof DecimalFormat)) {
+            return false;
+        }
+        DecimalFormat obj = (DecimalFormat) object;
+
+        if(obj.addr == this.addr) {
+            return true;
+        }
+        
+        boolean result = super.equals(object);
+
+        
+        result &= obj.toPattern().equals(this.toPattern());
+        result &= obj.isDecimalSeparatorAlwaysShown() == this.isDecimalSeparatorAlwaysShown();
+        result &= obj.getGroupingSize() == this.getGroupingSize();
+        result &= obj.getMultiplier() == this.getMultiplier();
+        result &= obj.getNegativePrefix().equals(this.getNegativePrefix());
+        result &= obj.getNegativeSuffix().equals(this.getNegativeSuffix());
+        result &= obj.getPositivePrefix().equals(this.getPositivePrefix());
+        result &= obj.getPositiveSuffix().equals(this.getPositiveSuffix());
+        result &= obj.getMaximumIntegerDigits() == this.getMaximumIntegerDigits();
+        result &= obj.getMaximumFractionDigits() == this.getMaximumFractionDigits();
+        result &= obj.getMinimumIntegerDigits() == this.getMinimumIntegerDigits();
+        result &= obj.getMinimumFractionDigits() == this.getMinimumFractionDigits();
+        result &= obj.isGroupingUsed() == this.isGroupingUsed();
+        Currency objCurr = obj.getCurrency();
+        Currency thisCurr = this.getCurrency();
+        if(objCurr != null) {
+            result &= objCurr.getCurrencyCode().equals(thisCurr.getCurrencyCode());
+            result &= objCurr.getSymbol().equals(thisCurr.getSymbol());
+            result &= objCurr.getDefaultFractionDigits() == thisCurr.getDefaultFractionDigits();
+        } else {
+            result &= thisCurr == null;
+        }
+        result &= obj.getDecimalFormatSymbols().equals(this.getDecimalFormatSymbols());
+        
+        return result;
+    }
+
+    @Override
+    public StringBuffer format(Object value, StringBuffer buffer, FieldPosition field) {
+        
+        if(!(value instanceof Number)) {
+            throw new IllegalArgumentException();
+        }
+        if(buffer == null || field == null) {
+            throw new NullPointerException();
+        }
+        
+        String fieldType = null;
+        if(field != null) {
+            fieldType = getFieldType(field.getFieldAttribute());
+        }
+        
+        Number number = (Number) value;
+        
+        if(number instanceof BigInteger) {
+            BigInteger valBigInteger = (BigInteger) number;
+            String result = NativeDecimalFormat.format(this.addr, 
+                    valBigInteger.toString(10), field, fieldType, null, 0);
+            return buffer.append(result);
+        } else if(number instanceof BigDecimal) {
+            BigDecimal valBigDecimal = (BigDecimal) number;
+            String result = NativeDecimalFormat.format(this.addr, 
+                    valBigDecimal.unscaledValue().toString(10), field, 
+                    fieldType, null, valBigDecimal.scale());
+            return buffer.append(result);
+        } else {
+            double dv = number.doubleValue();
+            long lv = number.longValue();
+            if (dv == lv) {
+                String result = NativeDecimalFormat.format(this.addr, lv, field,
+                        fieldType, null);
+                return buffer.append(result);
+            }
+            String result = NativeDecimalFormat.format(this.addr, dv, field, 
+                    fieldType, null);
+            return buffer.append(result);
+        }
+    }
+
+    @Override
+    public StringBuffer format(long value, StringBuffer buffer, FieldPosition field) {
+
+        if(buffer == null) {
+            throw new NullPointerException();
+        }
+        
+        String fieldType = null;
+        
+        if(field != null) {
+            fieldType = getFieldType(field.getFieldAttribute());
+        }
+        
+        String result = NativeDecimalFormat.format(this.addr, value, field, 
+                fieldType, null);
+        
+        buffer.append(result.toCharArray(), 0, result.length());
+        
+        return buffer;
+    }
+
+    @Override
+    public StringBuffer format(double value, StringBuffer buffer, FieldPosition field) {
+
+        if(buffer == null) {
+            throw new NullPointerException();
+        }
+        
+        String fieldType = null;
+        
+        if(field != null) {
+            fieldType = getFieldType(field.getFieldAttribute());
+        }
+        
+        String result = NativeDecimalFormat.format(this.addr, value, field, 
+                fieldType, null);
+        
+        buffer.append(result.toCharArray(), 0, result.length());
+        
+        return buffer;
+    }
+
+    public void applyLocalizedPattern(String pattern) {
+        if (pattern == null) {
+            throw new NullPointerException("pattern was null");
+        }
+        try {
+            NativeDecimalFormat.applyPatternImpl(this.addr, false, pattern);
+        } catch(RuntimeException re) {
+            throw new IllegalArgumentException(
+                    "applying localized pattern failed for pattern: " + pattern, re);
+        }
+    }
+
+    public void applyPattern(String pattern) {
+        if (pattern == null) {
+            throw new NullPointerException("pattern was null");
+        }
+        try {
+            NativeDecimalFormat.applyPatternImpl(this.addr, false, pattern);
+        } catch(RuntimeException re) {
+            throw new IllegalArgumentException(
+                    "applying pattern failed for pattern: " + pattern, re);
+        }
+    }
+
+    @Override
+    public AttributedCharacterIterator formatToCharacterIterator(Object object) {
+        if (!(object instanceof Number)) {
+            throw new IllegalArgumentException();
+        }
+        Number number = (Number) object;
+        String text = null;
+        StringBuffer attributes = new StringBuffer();
+        
+        if(number instanceof BigInteger) {
+            BigInteger valBigInteger = (BigInteger) number;
+            if(valBigInteger.compareTo(
+                    new BigInteger(String.valueOf(Long.MAX_VALUE))) > 0) {
+                throw(new UnsupportedOperationException(
+                        "Number too big. BigInteger > Long.MAX_VALUE not yet supported."));
+            }
+            text = NativeDecimalFormat.format(this.addr, 
+                    valBigInteger.longValue(), null, null, attributes);
+        } else if(number instanceof BigDecimal) {
+            BigDecimal valBigDecimal = (BigDecimal) number;
+            if(valBigDecimal.compareTo(
+                    new BigDecimal(String.valueOf(Double.MAX_VALUE))) > 0) {
+                throw(new UnsupportedOperationException(
+                        "Number too big. BigDecimal > Double.MAX_VALUE not yet supported."));
+            }
+            text = NativeDecimalFormat.format(this.addr, 
+                    valBigDecimal.doubleValue(), null, null, attributes);
+        } else {
+            double dv = number.doubleValue();
+            long lv = number.longValue();
+            if (dv == lv) {
+                text = NativeDecimalFormat.format(this.addr, lv, null,
+                        null, attributes);
+            } else {
+                text = NativeDecimalFormat.format(this.addr, dv, null, 
+                        null, attributes);
+            }
+        }
+        
+        AttributedString as = new AttributedString(text.toString());
+
+        String[] attrs = attributes.toString().split(";");
+        // add NumberFormat field attributes to the AttributedString
+        int size = attrs.length / 3;
+        if(size * 3 != attrs.length) {
+            return as.getIterator();
+        }
+        for (int i = 0; i < size; i++) {
+            Format.Field attribute = getField(attrs[3*i]);
+            as.addAttribute(attribute, attribute, Integer.parseInt(attrs[3*i+1]),
+                    Integer.parseInt(attrs[3*i+2]));
+        }
+   
+        // return the CharacterIterator from AttributedString
+        return as.getIterator();
+    }
+
+    public String toLocalizedPattern() {
+        return NativeDecimalFormat.toPatternImpl(this.addr, true);
+    }
+
+    public String toPattern() {
+        return NativeDecimalFormat.toPatternImpl(this.addr, false);
+    }
+
+    @Override
+    public Number parse(String string, ParsePosition position) {
+        return NativeDecimalFormat.parse(addr, string, position);
+    }
+    
+    // start getter and setter
+
+    @Override
+    public int getMaximumFractionDigits() {
+        return NativeDecimalFormat.getAttribute(this .addr, 
+                UNumberFormatAttribute.UNUM_MAX_FRACTION_DIGITS.ordinal());
+    }
+
+    @Override
+    public int getMaximumIntegerDigits() {
+        return NativeDecimalFormat.getAttribute(this .addr, 
+                UNumberFormatAttribute.UNUM_MAX_INTEGER_DIGITS.ordinal());
+    }
+
+    @Override
+    public int getMinimumFractionDigits() {
+        return NativeDecimalFormat.getAttribute(this .addr, 
+                UNumberFormatAttribute.UNUM_MIN_FRACTION_DIGITS.ordinal());
+    }
+
+    @Override
+    public int getMinimumIntegerDigits() {
+        return NativeDecimalFormat.getAttribute(this .addr, 
+                UNumberFormatAttribute.UNUM_MIN_INTEGER_DIGITS.ordinal());
+    }
+
+    @Override
+    public Currency getCurrency() {
+        return this.symbols.getCurrency();
+    }
+
+    public int getGroupingSize() {
+        return NativeDecimalFormat.getAttribute(this.addr, 
+                UNumberFormatAttribute.UNUM_GROUPING_SIZE.ordinal());
+    }
+
+    public int getMultiplier() {
+        return NativeDecimalFormat.getAttribute(this.addr, 
+                UNumberFormatAttribute.UNUM_MULTIPLIER.ordinal());
+    }
+
+    public String getNegativePrefix() {
+        return NativeDecimalFormat.getTextAttribute(this.addr, 
+                UNumberFormatTextAttribute.UNUM_NEGATIVE_PREFIX.ordinal());
+    }
+
+    public String getNegativeSuffix() {
+        return NativeDecimalFormat.getTextAttribute(this.addr, 
+                UNumberFormatTextAttribute.UNUM_NEGATIVE_SUFFIX.ordinal());
+    }
+
+    public String getPositivePrefix() {
+        return NativeDecimalFormat.getTextAttribute(this.addr, 
+                UNumberFormatTextAttribute.UNUM_POSITIVE_PREFIX.ordinal());
+    }
+
+    public String getPositiveSuffix() {
+        return NativeDecimalFormat.getTextAttribute(this.addr, 
+                UNumberFormatTextAttribute.UNUM_POSITIVE_SUFFIX.ordinal());
+    }
+
+    public boolean isDecimalSeparatorAlwaysShown() {
+        return NativeDecimalFormat.getAttribute(this.addr, 
+                UNumberFormatAttribute.UNUM_DECIMAL_ALWAYS_SHOWN.ordinal()) != 0;
+    }
+
+    @Override
+    public boolean isParseIntegerOnly() {
+        return NativeDecimalFormat.getAttribute(this.addr, 
+                UNumberFormatAttribute.UNUM_PARSE_INT_ONLY.ordinal()) != 0;
+    }
+
+    @Override
+    public boolean isGroupingUsed() {
+        return NativeDecimalFormat.getAttribute(this.addr, 
+                UNumberFormatAttribute.UNUM_GROUPING_USED.ordinal()) != 0;
+    }
+
+    public DecimalFormatSymbols getDecimalFormatSymbols() {
+        return this.symbols;
+    }
+
+    public void setDecimalFormatSymbols(DecimalFormatSymbols icuSymbols) {
+        this.symbols = icuSymbols;
+    }
+
+    public void setDecimalSeparatorAlwaysShown(boolean value) {
+        int i = value ? -1 : 0;
+        NativeDecimalFormat.setAttribute(this.addr, 
+                UNumberFormatAttribute.UNUM_DECIMAL_ALWAYS_SHOWN.ordinal(), i);
+    }
+
+    @Override
+    public void setCurrency(Currency currency) {
+        this.symbols.setCurrency(currency);
+    }
+
+    public void setGroupingSize(int value) {
+        NativeDecimalFormat.setAttribute(this.addr,
+                UNumberFormatAttribute.UNUM_GROUPING_SIZE.ordinal(), value);
+    }
+
+    @Override
+    public void setGroupingUsed(boolean value) {
+        int i = value ? -1 : 0;
+        NativeDecimalFormat.setAttribute(this.addr,
+                UNumberFormatAttribute.UNUM_GROUPING_USED.ordinal(), i);
+    }
+
+    @Override
+    public void setMaximumFractionDigits(int value) {
+        NativeDecimalFormat.setAttribute(this.addr,
+                UNumberFormatAttribute.UNUM_MAX_FRACTION_DIGITS.ordinal(), value);
+    }
+
+    @Override
+    public void setMaximumIntegerDigits(int value) {
+        NativeDecimalFormat.setAttribute(this.addr,
+                UNumberFormatAttribute.UNUM_MAX_INTEGER_DIGITS.ordinal(), value);
+    }
+
+    @Override
+    public void setMinimumFractionDigits(int value) {
+        NativeDecimalFormat.setAttribute(this.addr,
+                UNumberFormatAttribute.UNUM_MIN_FRACTION_DIGITS.ordinal(), value);
+    }
+
+    @Override
+    public void setMinimumIntegerDigits(int value) {
+        NativeDecimalFormat.setAttribute(this.addr,
+                UNumberFormatAttribute.UNUM_MIN_INTEGER_DIGITS.ordinal(), value);
+    }
+
+    public void setMultiplier(int value) {
+        NativeDecimalFormat.setAttribute(this.addr,
+                UNumberFormatAttribute.UNUM_MULTIPLIER.ordinal(), value);
+    }
+
+    public void setNegativePrefix(String value) {
+        NativeDecimalFormat.setTextAttribute(this.addr,
+                UNumberFormatTextAttribute.UNUM_NEGATIVE_PREFIX.ordinal(), value);
+    }
+
+    public void setNegativeSuffix(String value) {
+        NativeDecimalFormat.setTextAttribute(this.addr,
+                UNumberFormatTextAttribute.UNUM_NEGATIVE_SUFFIX.ordinal(), value);
+    }
+
+    public void setPositivePrefix(String value) {
+        NativeDecimalFormat.setTextAttribute(this.addr,
+                UNumberFormatTextAttribute.UNUM_POSITIVE_PREFIX.ordinal(), value);
+    }
+
+    public void setPositiveSuffix(String value) {
+        NativeDecimalFormat.setTextAttribute(this.addr,
+                UNumberFormatTextAttribute.UNUM_POSITIVE_SUFFIX.ordinal(), value);
+    }
+
+    @Override
+    public void setParseIntegerOnly(boolean value) {
+        int i = value ? -1 : 0;
+        NativeDecimalFormat.setAttribute(this.addr, 
+                UNumberFormatAttribute.UNUM_PARSE_INT_ONLY.ordinal(), i);
+    }
+    
+    static protected String getFieldType(Format.Field field) {
+        if(field == null) {
+            return null;
+        }
+        if(field.equals(NumberFormat.Field.SIGN)) {
+            return "sign";
+        }
+        if(field.equals(NumberFormat.Field.INTEGER)) {
+            return "integer";
+        }
+        if(field.equals(NumberFormat.Field.FRACTION)) {
+            return "fraction";
+        }
+        if(field.equals(NumberFormat.Field.EXPONENT)) {
+            return "exponent";
+        }
+        if(field.equals(NumberFormat.Field.EXPONENT_SIGN)) {
+            return "exponent_sign";
+        }
+        if(field.equals(NumberFormat.Field.EXPONENT_SYMBOL)) {
+            return "exponent_symbol";
+        }
+        if(field.equals(NumberFormat.Field.CURRENCY)) {
+            return "currency";
+        }
+        if(field.equals(NumberFormat.Field.GROUPING_SEPARATOR)) {
+            return "grouping_separator";
+        }
+        if(field.equals(NumberFormat.Field.DECIMAL_SEPARATOR)) {
+            return "decimal_separator";
+        }
+        if(field.equals(NumberFormat.Field.PERCENT)) {
+            return "percent";
+        }
+        if(field.equals(NumberFormat.Field.PERMILLE)) {
+            return "permille";
+        }
+        return null;
+    }
+    
+    protected Format.Field getField(String type) {
+        if(type.equals("")) {
+            return null;
+        }
+        if(type.equals("sign")) {
+            return NumberFormat.Field.SIGN;
+        }
+        if(type.equals("integer")) {
+            return NumberFormat.Field.INTEGER;
+        }
+        if(type.equals("fraction")) {
+            return NumberFormat.Field.FRACTION;
+        }
+        if(type.equals("exponent")) {
+            return NumberFormat.Field.EXPONENT;
+        }
+        if(type.equals("exponent_sign")) {
+            return NumberFormat.Field.EXPONENT_SIGN;
+        }
+        if(type.equals("exponent_symbol")) {
+            return NumberFormat.Field.EXPONENT_SYMBOL;
+        }
+        if(type.equals("currency")) {
+            return NumberFormat.Field.CURRENCY;
+        }
+        if(type.equals("grouping_separator")) {
+            return NumberFormat.Field.GROUPING_SEPARATOR;
+        }
+        if(type.equals("decimal_separator")) {
+            return NumberFormat.Field.DECIMAL_SEPARATOR;
+        }
+        if(type.equals("percent")) {
+            return NumberFormat.Field.PERCENT;
+        }
+        if(type.equals("permille")) {
+            return NumberFormat.Field.PERMILLE;
+        }
+        return null;
+    }
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
new file mode 100644
index 0000000..98463e4
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.text;
+
+import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatSymbol;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Currency;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+public class DecimalFormatSymbols {
+    
+    private int addr;
+    
+    private Locale loc;
+
+    private DecimalFormatSymbols(int addr, Locale loc) {
+        this.addr = addr;
+        this.loc = loc;
+    }
+    
+    public DecimalFormatSymbols(Locale locale) {
+        this.loc = locale;
+        ResourceBundle bundle = AccessController.
+        doPrivileged(new PrivilegedAction<ResourceBundle>() {
+            public ResourceBundle run() {
+            return ResourceBundle.getBundle(
+                    "org.apache.harmony.luni.internal.locale.Locale", loc); //$NON-NLS-1$
+            }
+        });
+        String pattern = bundle.getString("Number");
+        this.addr = NativeDecimalFormat.openDecimalFormatImpl(
+                locale.toString(), pattern);
+        String currSymbol = bundle.getString("CurrencySymbol");
+        String intCurrSymbol = bundle.getString("IntCurrencySymbol");
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(), currSymbol);
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal(), 
+                intCurrSymbol);
+    }
+    
+    @Override
+    public boolean equals(Object object) {
+        if(object == null) {
+            return false;
+        }
+        if(!(object instanceof DecimalFormatSymbols)) {
+            return false;
+        }
+        
+        DecimalFormatSymbols sym = (DecimalFormatSymbols) object;
+        
+        if(sym.addr == this.addr) {
+            return true;
+        }
+        
+        boolean result = true;
+        
+        Currency objCurr = sym.getCurrency();
+        Currency thisCurr = this.getCurrency();
+        if(objCurr != null) {
+            result &= objCurr.getCurrencyCode().equals(thisCurr.getCurrencyCode());
+            result &= objCurr.getSymbol().equals(thisCurr.getSymbol());
+            result &= objCurr.getDefaultFractionDigits() == thisCurr.getDefaultFractionDigits();
+        } else {
+            result &= thisCurr == null;
+        }
+        result &= sym.getCurrencySymbol().equals(this.getCurrencySymbol());
+        result &= sym.getDecimalSeparator() == this.getDecimalSeparator();
+        result &= sym.getDigit() == this.getDigit();
+        result &= sym.getGroupingSeparator() == this.getGroupingSeparator();
+        result &= sym.getInfinity().equals(this.getInfinity());
+        result &= sym.getInternationalCurrencySymbol().equals(
+                this.getInternationalCurrencySymbol());
+        result &= sym.getMinusSign() == this.getMinusSign();
+        result &= sym.getMonetaryDecimalSeparator() == 
+                this.getMonetaryDecimalSeparator();
+        result &= sym.getNaN().equals(this.getNaN());
+        result &= sym.getPatternSeparator() == this.getPatternSeparator();
+        result &= sym.getPercent() == this.getPercent();
+        result &= sym.getPerMill() == this.getPerMill();
+        result &= sym.getZeroDigit() == this.getZeroDigit();
+        
+        return result;
+    }
+
+    @Override
+    public Object clone() {
+        int addr = NativeDecimalFormat.cloneImpl(this.addr);
+        Locale loc = (Locale) this.loc.clone();
+        return new DecimalFormatSymbols(addr, loc);
+    }
+    
+    public void setCurrency(Currency currency) {
+        NativeDecimalFormat.setSymbol(this.addr,
+               UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(), 
+               currency.getSymbol());
+        NativeDecimalFormat.setSymbol(this.addr,
+               UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal(), 
+               currency.getCurrencyCode());
+    }
+
+    public void setCurrencySymbol(String symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(), 
+                symbol);
+    }
+
+    public void setDecimalSeparator(char symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_DECIMAL_SEPARATOR_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+
+    public void setDigit(char symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_DIGIT_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+
+    public void setGroupingSeparator(char symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_GROUPING_SEPARATOR_SYMBOL.ordinal(), 
+                "" + symbol);
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+
+    public void setInfinity(String symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_INFINITY_SYMBOL.ordinal(), 
+                symbol);
+    }
+
+    public void setInternationalCurrencySymbol(String symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal(), 
+                symbol);
+    }
+
+    public void setMinusSign(char symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_MINUS_SIGN_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+
+    public void setMonetaryDecimalSeparator(char symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_MONETARY_SEPARATOR_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+
+    public void setNaN(String symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_NAN_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+
+    public void setPatternSeparator(char symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_PATTERN_SEPARATOR_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+
+    public void setPercent(char symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_PERCENT_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+
+    public void setPerMill(char symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_PERMILL_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+
+    public void setZeroDigit(char symbol) {
+        NativeDecimalFormat.setSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_ZERO_DIGIT_SYMBOL.ordinal(), 
+                "" + symbol);
+    }
+ 
+    public Currency getCurrency() {
+        String curr = NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal());
+        if(curr.equals("") || curr.equals("\u00a4\u00a4")) {
+            return null;
+        }
+         return Currency.getInstance(curr);
+    }
+ 
+    public String getCurrencySymbol() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal());
+    }
+ 
+    public char getDecimalSeparator() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_DECIMAL_SEPARATOR_SYMBOL.ordinal())
+                .charAt(0);
+    }
+ 
+    public char getDigit() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_DIGIT_SYMBOL.ordinal())
+                .charAt(0);
+    }
+ 
+    public char getGroupingSeparator() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_GROUPING_SEPARATOR_SYMBOL.ordinal())
+                .charAt(0);
+    }
+ 
+    public String getInfinity() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_INFINITY_SYMBOL.ordinal());
+    }
+ 
+    public String getInternationalCurrencySymbol() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal());
+    }
+ 
+    public char getMinusSign() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_MINUS_SIGN_SYMBOL.ordinal())
+                .charAt(0);
+    }
+ 
+    public char getMonetaryDecimalSeparator() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_MONETARY_SEPARATOR_SYMBOL.ordinal())
+                .charAt(0);
+    }
+
+    public String getNaN() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_NAN_SYMBOL.ordinal());
+    }
+ 
+    public char getPatternSeparator() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_PATTERN_SEPARATOR_SYMBOL.ordinal())
+                .charAt(0);
+    }
+ 
+    public char getPercent() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_PERCENT_SYMBOL.ordinal())
+                .charAt(0);
+    }
+ 
+    public char getPerMill() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_PERMILL_SYMBOL.ordinal())
+                .charAt(0);
+    }
+
+    public char getZeroDigit() {
+        return NativeDecimalFormat.getSymbol(this.addr,
+                UNumberFormatSymbol.UNUM_ZERO_DIGIT_SYMBOL.ordinal())
+                .charAt(0);
+    }
+    
+    int getAddr() {
+        return this.addr;
+    }
+    
+    Locale getLocale() {
+        return this.loc;
+    }
+    
+    protected void finalize() {
+        NativeDecimalFormat.closeDecimalFormatImpl(this.addr);
+    }
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeBreakIterator.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeBreakIterator.java
new file mode 100644
index 0000000..c48f1d9
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeBreakIterator.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.text;
+ 
+public final class NativeBreakIterator
+{  
+    public NativeBreakIterator() {
+        
+    }
+
+    static String[] getAvailableLocalesImpl() {
+        int count =  getAvailableLocalesCountImpl();
+        String[] result = new String[count];
+        
+        for(int i = 0; i < count; i++) {
+            result[i] = getAvailableLocalesImpl(i);
+        }
+        return result;
+    }
+
+    private static native String getAvailableLocalesImpl(int i);
+    
+    private static native int getAvailableLocalesCountImpl();
+
+    static native int getCharacterInstanceImpl(String locale);
+    
+    static native int getWordInstanceImpl(String locale);
+    
+    static native int getLineInstanceImpl(String locale);
+    
+    static native int getSentenceInstanceImpl(String locale);
+
+    static native void closeBreakIteratorImpl(int biaddress);
+    
+    static native void setTextImpl(int biaddress, String text);
+    
+    static native int cloneImpl(int biaddress);
+    
+    static native int precedingImpl(int biaddress, int offset);
+
+    static native boolean isBoundaryImpl(int biaddress, int offset);
+
+    static native int nextImpl(int biaddress, int n);
+
+    static native int previousImpl(int biaddress);
+
+    static native int currentImpl(int biaddress);
+
+    static native int firstImpl(int biaddress);
+
+    static native int followingImpl(int biaddress, int offset);
+
+    static native int lastImpl(int biaddress);
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeCollation.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeCollation.java
new file mode 100644
index 0000000..8606a86
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeCollation.java
@@ -0,0 +1,263 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+/**
+* Package static class for declaring all native methods for collation use.
+* @author syn wee quek
+* @internal ICU 2.4
+*/
+    
+public final class NativeCollation
+{
+  // collator methods ---------------------------------------------
+  
+  public NativeCollation() {
+      
+  }
+    
+  /**
+  * Method to create a new C Collator using the default locale rules.
+  * @return new c collator
+  * @internal ICU 2.4
+  */
+  static native int openCollator();
+  
+  /**
+  * Method to create a new C Collator using the argument locale rules.
+  * @param locale locale name
+  * @return new c collator
+  * @internal ICU 2.4
+  */
+  static native int openCollator(String locale);
+  
+  /**
+  * Method to create a new C Collator using the argument rules.
+  * @param rules , set of collation rules
+  * @param normalizationmode default normalization mode
+  * @param collationstrength default collation strength
+  * @return new c collator
+  * @internal ICU 2.4
+  */
+  static native int openCollatorFromRules(String rules,
+                                           int normalizationmode,
+                                           int collationstrength);
+
+  /** 
+  * Close a C collator
+  * Once closed, a UCollatorOld should not be used.
+  * @param collatoraddress The UCollatorOld to close
+  * @internal ICU 2.4
+  */
+  static native void closeCollator(int collatoraddress);
+  
+  /**
+  * Compare two strings.
+  * The strings will be compared using the normalization mode and options
+  * specified in openCollator or openCollatorFromRules
+  * @param collatoraddress address of the c collator
+  * @param source The source string.
+  * @param target The target string.
+  * @return result of the comparison, Collation.EQUAL, 
+  *         Collation.GREATER or Collation.LESS
+  * @internal ICU 2.4
+  */
+  static native int compare(int collatoraddress, String source, 
+                            String target);
+                             
+  /**
+  * Get the normalization mode for this object.
+  * The normalization mode influences how strings are compared.
+  * @param collatoraddress 
+  * @return normalization mode; one of the values from Normalization
+  * @internal ICU 2.4
+  */
+  static native int getNormalization(int collatoraddress);
+
+  /**
+  * Set the normalization mode used int this object
+  * The normalization mode influences how strings are compared.
+  * @param collatoraddress the address of the C collator
+  * @param normalizationmode desired normalization mode; one of the values 
+  *        from Normalization
+  * @internal ICU 2.4
+  */
+  static native void setNormalization(int collatoraddress, 
+                                      int normalizationmode);
+
+  /**
+  * Get the collation rules from a UCollator.
+  * The rules will follow the rule syntax.
+  * @param collatoraddress the address of the C collator
+  * @return collation rules.
+  * @internal ICU 2.4
+  */
+  static native String getRules(int collatoraddress);
+
+  /**
+  * Get a sort key for the argument string
+  * Sort keys may be compared using java.util.Arrays.equals
+  * @param collatoraddress address of the C collator
+  * @param source string for key to be generated
+  * @return sort key
+  * @internal ICU 2.4
+  */
+  static native byte[] getSortKey(int collatoraddress, String source);
+                                   
+  /**
+  * Gets the version information for collation. 
+  * @param collatoraddress address of the C collator
+  * @return version information
+  * @internal ICU 2.4
+  */
+  // private native String getVersion(int collatoraddress);
+
+  /**
+  * Universal attribute setter.
+  * @param collatoraddress address of the C collator
+  * @param type type of attribute to be set
+  * @param value attribute value
+  * @exception RuntimeException when error occurs while setting attribute value
+  * @internal ICU 2.4
+  */
+  static native void setAttribute(int collatoraddress, int type, int value);
+
+  /**
+  * Universal attribute getter
+  * @param collatoraddress address of the C collator
+  * @param type type of attribute to be set
+  * @return attribute value
+  * @exception RuntimeException thrown when error occurs while getting attribute value
+  * @internal ICU 2.4
+  */
+  static native int getAttribute(int collatoraddress, int type);
+
+  /**
+  * Thread safe cloning operation
+  * @param collatoraddress address of C collator to be cloned
+  * @return address of the new clone
+  * @exception RuntimeException thrown when error occurs while cloning
+  * @internal ICU 2.4
+  */
+  static native int safeClone(int collatoraddress);
+  
+  /** 
+  * Create a CollationElementIterator object that will iterator over the 
+  * elements in a string, using the collation rules defined in this 
+  * RuleBasedCollator
+  * @param collatoraddress address of C collator
+  * @param source string to iterate over
+  * @return address of C collationelementiterator
+  * @internal ICU 2.4
+  */
+  static native int getCollationElementIterator(int collatoraddress, 
+                                                 String source);
+                                                 
+  /**
+  * Returns a hash of this collation object
+  * @param collatoraddress address of C collator
+  * @return hash of this collation object
+  * @internal ICU 2.4
+  */
+  static native int hashCode(int collatoraddress);
+
+    
+  // collationelementiterator methods -------------------------------------
+  
+  /**
+  * Close a C collation element iterator.
+  * @param address of C collation element iterator to close.
+  * @internal ICU 2.4
+  */
+  static native void closeElements(int address);
+
+  /**
+  * Reset the collation elements to their initial state.
+  * This will move the 'cursor' to the beginning of the text.
+  * @param address of C collation element iterator to reset.
+  * @internal ICU 2.4
+  */
+  static native void reset(int address);
+
+  /**
+  * Get the ordering priority of the next collation element in the text.
+  * A single character may contain more than one collation element.
+  * @param address if C collation elements containing the text.
+  * @return next collation elements ordering, or NULLORDER if the end of the 
+  *         text is reached.
+  * @internal ICU 2.4
+  */
+  static native int next(int address);
+
+  /**
+  * Get the ordering priority of the previous collation element in the text.
+  * A single character may contain more than one collation element.
+  * @param address of the C collation element iterator containing the text.
+  * @return previous collation element ordering, or NULLORDER if the end of 
+  *         the text is reached.
+  * @internal ICU 2.4
+  */
+  static native int previous(int address);
+
+  /**
+  * Get the maximum length of any expansion sequences that end with the 
+  * specified comparison order.
+  * @param address of the C collation element iterator containing the text.
+  * @param order collation order returned by previous or next.
+  * @return maximum length of any expansion sequences ending with the 
+  *         specified order.
+  * @internal ICU 2.4
+  */
+  static native int getMaxExpansion(int address, int order);
+
+  /**
+  * Set the text containing the collation elements.
+  * @param address of the C collation element iterator to be set
+  * @param source text containing the collation elements.
+  * @internal ICU 2.4
+  */
+  static native void setText(int address, String source);
+
+  /**
+  * Get the offset of the current source character.
+  * This is an offset into the text of the character containing the current
+  * collation elements.
+  * @param address of the C collation elements iterator to query.
+  * @return offset of the current source character.
+  * @internal ICU 2.4
+  */
+  static native int getOffset(int address);
+
+  /**
+  * Set the offset of the current source character.
+  * This is an offset into the text of the character to be processed.
+  * @param address of the C collation element iterator to set.
+  * @param offset The desired character offset.
+  * @internal ICU 2.4
+  */
+  static native void setOffset(int address, int offset);
+
+  // BEGIN android-added
+  static String[] getAvailableLocalesImpl() {
+      int count =  getAvailableLocalesCountImpl();
+      String[] result = new String[count];
+      
+      for(int i = 0; i < count; i++) {
+          result[i] = getAvailableLocalesImpl(i);
+      }
+      return result;
+  }
+  
+  private static native String getAvailableLocalesImpl(int i);
+  
+  private static native int getAvailableLocalesCountImpl();
+  // END android-added
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
new file mode 100644
index 0000000..b3b9265
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.text;
+
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+
+public final class NativeDecimalFormat {
+
+    enum UNumberFormatSymbol {
+        UNUM_DECIMAL_SEPARATOR_SYMBOL, 
+        UNUM_GROUPING_SEPARATOR_SYMBOL, 
+        UNUM_PATTERN_SEPARATOR_SYMBOL, 
+        UNUM_PERCENT_SYMBOL,
+        UNUM_ZERO_DIGIT_SYMBOL, 
+        UNUM_DIGIT_SYMBOL, 
+        UNUM_MINUS_SIGN_SYMBOL, 
+        UNUM_PLUS_SIGN_SYMBOL,
+        UNUM_CURRENCY_SYMBOL, 
+        UNUM_INTL_CURRENCY_SYMBOL, 
+        UNUM_MONETARY_SEPARATOR_SYMBOL, 
+        UNUM_EXPONENTIAL_SYMBOL,
+        UNUM_PERMILL_SYMBOL, 
+        UNUM_PAD_ESCAPE_SYMBOL, 
+        UNUM_INFINITY_SYMBOL, 
+        UNUM_NAN_SYMBOL,
+        UNUM_SIGNIFICANT_DIGIT_SYMBOL, 
+        UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, 
+        UNUM_FORMAT_SYMBOL_COUNT
+    }
+    
+    enum UNumberFormatAttribute {
+        UNUM_PARSE_INT_ONLY, 
+        UNUM_GROUPING_USED, 
+        UNUM_DECIMAL_ALWAYS_SHOWN, 
+        UNUM_MAX_INTEGER_DIGITS,
+        UNUM_MIN_INTEGER_DIGITS, 
+        UNUM_INTEGER_DIGITS, 
+        UNUM_MAX_FRACTION_DIGITS, 
+        UNUM_MIN_FRACTION_DIGITS,
+        UNUM_FRACTION_DIGITS,
+        UNUM_MULTIPLIER, 
+        UNUM_GROUPING_SIZE, 
+        UNUM_ROUNDING_MODE,
+        UNUM_ROUNDING_INCREMENT, 
+        UNUM_FORMAT_WIDTH, 
+        UNUM_PADDING_POSITION, 
+        UNUM_SECONDARY_GROUPING_SIZE,
+        UNUM_SIGNIFICANT_DIGITS_USED, 
+        UNUM_MIN_SIGNIFICANT_DIGITS, 
+        UNUM_MAX_SIGNIFICANT_DIGITS, 
+        UNUM_LENIENT_PARSE
+    }
+
+    enum UNumberFormatTextAttribute {
+        UNUM_POSITIVE_PREFIX, 
+        UNUM_POSITIVE_SUFFIX, 
+        UNUM_NEGATIVE_PREFIX, 
+        UNUM_NEGATIVE_SUFFIX,
+        UNUM_PADDING_CHARACTER, 
+        UNUM_CURRENCY_CODE, 
+        UNUM_DEFAULT_RULESET, 
+        UNUM_PUBLIC_RULESETS
+    }
+    
+    static native int openDecimalFormatImpl(String locale, String pattern);
+
+    static native void closeDecimalFormatImpl(int addr);
+    
+    static native int cloneImpl(int addr);
+    
+    static native void setSymbol(int addr, int symbol, String str);
+    
+    static native String getSymbol(int addr, int symbol);
+    
+    static native void setAttribute(int addr, int symbol, int i);
+    
+    static native int getAttribute(int addr, int symbol);
+
+    static native void setTextAttribute(int addr, int symbol, String str);
+
+    static native String getTextAttribute(int addr, int symbol);
+
+    static native void applyPatternImpl(int addr, boolean localized, String pattern);
+
+    static native String toPatternImpl(int addr, boolean localized);
+    
+    static native String format(int addr, long value, FieldPosition position, String fieldType, StringBuffer attributes);
+
+    static native String format(int addr, double value, FieldPosition position, String fieldType, StringBuffer attributes);
+
+    static native String format(int addr, String value, FieldPosition position, String fieldType, StringBuffer attributes, int scale);
+    
+    static native Number parse(int addr, String string, ParsePosition position);
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedBreakIterator.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedBreakIterator.java
new file mode 100644
index 0000000..4d38f2b
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedBreakIterator.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.text;
+
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+
+public class RuleBasedBreakIterator extends BreakIterator {
+
+    private CharacterIterator charIter;
+    
+    private int addr;
+
+    RuleBasedBreakIterator(int iterAddr, int type) {
+        this.addr = iterAddr;
+        this.type = type;
+        this.charIter = new StringCharacterIterator("");
+    }
+    
+    @Override
+    public Object clone() {
+        int cloneAddr = NativeBreakIterator.cloneImpl(this.addr);
+        RuleBasedBreakIterator rbbi = 
+                new RuleBasedBreakIterator(cloneAddr, this.type);
+        
+        rbbi.charIter = this.charIter;
+        
+        return rbbi;
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        if(object == null) {
+            return false;
+        }
+        
+        if(!(object instanceof RuleBasedBreakIterator)) {
+            return false;
+        }
+        
+        CharacterIterator iter = ((RuleBasedBreakIterator) object).charIter;
+        
+        boolean result = this.type == ((RuleBasedBreakIterator) object).type;
+        
+        return result && iter.equals(this.charIter);
+    }
+    
+    @Override
+    public int current() {
+        return NativeBreakIterator.currentImpl(this.addr);
+    }
+
+    @Override
+    public int first() {
+        return NativeBreakIterator.firstImpl(this.addr);
+    }
+
+    @Override
+    public int following(int offset) {
+        return NativeBreakIterator.followingImpl(this.addr, offset);
+    }
+
+    @Override
+    public CharacterIterator getText() {
+        int newLoc = NativeBreakIterator.currentImpl(this.addr);
+        this.charIter.setIndex(newLoc);
+        return this.charIter;
+    }
+
+    @Override
+    public int last() {
+        return NativeBreakIterator.lastImpl(this.addr);
+    }
+    
+    @Override
+    public int next(int n) {
+        return NativeBreakIterator.nextImpl(this.addr, n);
+    }
+
+    @Override
+    public int next() {
+        return NativeBreakIterator.nextImpl(this.addr, 1);
+    }
+    
+    @Override
+    public int previous() {
+        return NativeBreakIterator.previousImpl(this.addr);
+    }
+
+    @Override
+    public void setText(CharacterIterator newText) {
+        this.charIter = newText;
+
+        StringBuilder sb = new StringBuilder();
+        
+        char c = newText.first();
+        while(c != CharacterIterator.DONE) {
+            sb.append(c);
+            c = newText.next();
+        }
+
+        NativeBreakIterator.setTextImpl(this.addr, sb.toString());
+    }
+
+    protected void finalize() {
+        NativeBreakIterator.closeBreakIteratorImpl(this.addr);
+    }
+
+    @Override
+    public boolean isBoundary(int offset) {
+        return NativeBreakIterator.isBoundaryImpl(this.addr, offset);
+    }
+
+    @Override
+    public int preceding(int offset) {
+        return NativeBreakIterator.precedingImpl(this.addr, offset);
+    }
+
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedCollator.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedCollator.java
new file mode 100644
index 0000000..9931f2d
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedCollator.java
@@ -0,0 +1,705 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+
+package com.ibm.icu4jni.text;
+
+import java.util.Locale;
+import java.text.CharacterIterator;
+import java.text.ParseException;
+import com.ibm.icu4jni.common.ErrorCode;
+
+/**
+* Concrete implementation class for Collation.
+* <p>
+* The collation table is composed of a list of collation rules, where each
+* rule is of three forms:
+* <pre>
+*    < modifier >
+*    < relation > < text-argument >
+*    < reset > < text-argument >
+* </pre>
+* <p>
+* <code>RuleBasedCollator</code> has the following restrictions for efficiency 
+* (other subclasses may be used for more complex languages) :
+* <ol>
+* <li> If a French secondary ordering is specified it applies to the whole 
+*      collator object.
+* <li> All non-mentioned Unicode characters are at the end of the collation 
+*      order.
+* <li> If a character is not located in the RuleBasedCollator, the default 
+*      Unicode Collation Algorithm (UCA) rulebased table is automatically 
+*      searched as a backup.
+* </ol>
+*
+* The following demonstrates how to create your own collation rules:
+* <UL Type=disc>
+*    <LI><strong>Text-Argument</strong>: A text-argument is any sequence of
+*        characters, excluding special characters (that is, common whitespace 
+*        characters [0009-000D, 0020] and rule syntax characters [0021-002F, 
+*        003A-0040, 005B-0060, 007B-007E]). If those characters are desired, 
+*        you can put them in single quotes (e.g. ampersand => '&'). Note that 
+*        unquoted white space characters are ignored; e.g. <code>b c</code> is 
+*        treated as <code>bc</code>.
+*    <LI><strong>Modifier</strong>: There is a single modifier which is used 
+*        to specify that all accents (secondary differences) are backwards.
+*        <p>'@' : Indicates that accents are sorted backwards, as in French.
+*    <LI><strong>Relation</strong>: The relations are the following:
+*        <UL Type=square>
+*            <LI>'<' : Greater, as a letter difference (primary)
+*            <LI>';' : Greater, as an accent difference (secondary)
+*            <LI>',' : Greater, as a case difference (tertiary)
+*            <LI>'=' : Equal
+*        </UL>
+*    <LI><strong>Reset</strong>: There is a single reset which is used 
+*        primarily for contractions and expansions, but which can also be used 
+*        to add a modification at the end of a set of rules.
+*        <p>'&' : Indicates that the next rule follows the position to where
+*            the reset text-argument would be sorted.
+* </UL>
+*
+* <p>
+* This sounds more complicated than it is in practice. For example, the
+* following are equivalent ways of expressing the same thing:
+* <blockquote>
+* <pre>
+* a < b < c
+* a < b & b < c
+* a < c & a < b
+* </pre>
+* </blockquote>
+* Notice that the order is important, as the subsequent item goes immediately
+* after the text-argument. The following are not equivalent:
+* <blockquote>
+* <pre>
+* a < b & a < c
+* a < c & a < b
+* </pre>
+* </blockquote>
+* Either the text-argument must already be present in the sequence, or some
+* initial substring of the text-argument must be present. (e.g. "a < b & ae <
+* e" is valid since "a" is present in the sequence before "ae" is reset). In
+* this latter case, "ae" is not entered and treated as a single character;
+* instead, "e" is sorted as if it were expanded to two characters: "a"
+* followed by an "e". This difference appears in natural languages: in
+* traditional Spanish "ch" is treated as though it contracts to a single
+* character (expressed as "c < ch < d"), while in traditional German a-umlaut 
+* is treated as though it expanded to two characters (expressed as "a,A < b,B 
+* ... & ae;? & AE;?"). [? and ? are, of course, the escape sequences for 
+* a-umlaut.]
+* <p>
+* <strong>Ignorable Characters</strong>
+* <p>
+* For ignorable characters, the first rule must start with a relation (the
+* examples we have used above are really fragments; "a < b" really should be
+* "< a < b"). If, however, the first relation is not "<", then all the all
+* text-arguments up to the first "<" are ignorable. For example, ", - < a < b"
+* makes "-" an ignorable character, as we saw earlier in the word
+* "black-birds". In the samples for different languages, you see that most
+* accents are ignorable.
+*
+* <p><strong>Normalization and Accents</strong>
+* <p>
+* <code>RuleBasedCollator</code> automatically processes its rule table to
+* include both pre-composed and combining-character versions of accented 
+* characters. Even if the provided rule string contains only base characters 
+* and separate combining accent characters, the pre-composed accented 
+* characters matching all canonical combinations of characters from the rule 
+* string will be entered in the table.
+* <p>
+* This allows you to use a RuleBasedCollator to compare accented strings even 
+* when the collator is set to NO_DECOMPOSITION. However, if the strings to be 
+* collated contain combining sequences that may not be in canonical order, you 
+* should set the collator to CANONICAL_DECOMPOSITION to enable sorting of 
+* combining sequences.
+* For more information, see
+* <A HREF="http://www.aw.com/devpress">The Unicode Standard, Version 3.0</A>.)
+*
+* <p><strong>Errors</strong>
+* <p>
+* The following are errors:
+* <UL Type=disc>
+*     <LI>A text-argument contains unquoted punctuation symbols
+*        (e.g. "a < b-c < d").
+*     <LI>A relation or reset character not followed by a text-argument
+*        (e.g. "a < , b").
+*     <LI>A reset where the text-argument (or an initial substring of the
+*         text-argument) is not already in the sequence or allocated in the 
+*         default UCA table.
+*         (e.g. "a < b & e < f")
+* </UL>
+* If you produce one of these errors, a <code>RuleBasedCollator</code> throws
+* a <code>ParseException</code>.
+*
+* <p><strong>Examples</strong>
+* <p>Simple:     "< a < b < c < d"
+* <p>Norwegian:  "< a,A< b,B< c,C< d,D< e,E< f,F< g,G< h,H< i,I< j,J
+*                 < k,K< l,L< m,M< n,N< o,O< p,P< q,Q< r,R< s,S< t,T
+*                < u,U< v,V< w,W< x,X< y,Y< z,Z
+*                 < ?=a?,?=A?
+*                 ;aa,AA< ?,?< ?,?"
+*
+* <p>
+* Normally, to create a rule-based Collator object, you will use
+* <code>Collator</code>'s factory method <code>getInstance</code>.
+* However, to create a rule-based Collator object with specialized rules 
+* tailored to your needs, you construct the <code>RuleBasedCollator</code>
+* with the rules contained in a <code>String</code> object. For example:
+* <blockquote>
+* <pre>
+* String Simple = "< a < b < c < d";
+* RuleBasedCollator mySimple = new RuleBasedCollator(Simple);
+* </pre>
+* </blockquote>
+* Or:
+* <blockquote>
+* <pre>
+* String Norwegian = "< a,A< b,B< c,C< d,D< e,E< f,F< g,G< h,H< i,I< j,J" +
+*                 "< k,K< l,L< m,M< n,N< o,O< p,P< q,Q< r,R< s,S< t,T" +
+*                 "< u,U< v,V< w,W< x,X< y,Y< z,Z" +
+*                 "< ?=a?,?=A?" +
+*                 ";aa,AA< ?,?< ?,?";
+* RuleBasedCollator myNorwegian = new RuleBasedCollator(Norwegian);
+* </pre>
+* </blockquote>
+*
+* <p>
+* Combining <code>Collator</code>s is as simple as concatenating strings.
+* Here's an example that combines two <code>Collator</code>s from two
+* different locales:
+* <blockquote>
+* <pre>
+* // Create an en_US Collator object
+* RuleBasedCollator en_USCollator = (RuleBasedCollator)
+*     Collator.getInstance(new Locale("en", "US", ""));
+* // Create a da_DK Collator object
+* RuleBasedCollator da_DKCollator = (RuleBasedCollator)
+*     Collator.getInstance(new Locale("da", "DK", ""));
+* // Combine the two
+* // First, get the collation rules from en_USCollator
+* String en_USRules = en_USCollator.getRules();
+* // Second, get the collation rules from da_DKCollator
+* String da_DKRules = da_DKCollator.getRules();
+* RuleBasedCollator newCollator =
+*     new RuleBasedCollator(en_USRules + da_DKRules);
+* // newCollator has the combined rules
+* </pre>
+* </blockquote>
+*
+* <p>
+* Another more interesting example would be to make changes on an existing
+* table to create a new <code>Collator</code> object.  For example, add
+* "& C < ch, cH, Ch, CH" to the <code>en_USCollator</code> object to create
+* your own:
+* <blockquote>
+* <pre>
+* // Create a new Collator object with additional rules
+* String addRules = "& C < ch, cH, Ch, CH";
+* RuleBasedCollator myCollator =
+*     new RuleBasedCollator(en_USCollator + addRules);
+* // myCollator contains the new rules
+* </pre>
+* </blockquote>
+*
+* <p>
+* The following example demonstrates how to change the order of
+* non-spacing accents,
+* <blockquote>
+* <pre>
+* // old rule
+* String oldRules = "=?;?;?"    // main accents Diaeresis 00A8, Macron 00AF
+*                               // Acute 00BF
+*                 + "< a , A ; ae, AE ; ? , ?"
+*                 + "< b , B < c, C < e, E & C < d, D";
+* // change the order of accent characters
+* String addOn = "& ?;?;?;"; // Acute 00BF, Macron 00AF, Diaeresis 00A8
+* RuleBasedCollator myCollator = new RuleBasedCollator(oldRules + addOn);
+* </pre>
+* </blockquote>
+*
+* <p>
+* The last example shows how to put new primary ordering in before the
+* default setting. For example, in Japanese <code>Collator</code>, you
+* can either sort English characters before or after Japanese characters,
+* <blockquote>
+* <pre>
+* // get en_US Collator rules
+* RuleBasedCollator en_USCollator = 
+*                      (RuleBasedCollator)Collator.getInstance(Locale.US);
+* // add a few Japanese character to sort before English characters
+* // suppose the last character before the first base letter 'a' in
+* // the English collation rule is ?
+* String jaString = "& \\u30A2 , \\u30FC < \\u30C8";
+* RuleBasedCollator myJapaneseCollator = new
+*     RuleBasedCollator(en_USCollator.getRules() + jaString);
+* </pre>
+* </blockquote>
+* <P>
+* @author syn wee quek
+* @stable ICU 2.4 
+*/
+    
+public final class RuleBasedCollator extends Collator 
+{
+  // public constructors ------------------------------------------
+  
+  /**
+  * RuleBasedCollator constructor. This takes the table rules and builds a 
+  * collation table out of them. Please see RuleBasedCollator class
+  * description for more details on the collation rule syntax.
+  * @param rules the collation rules to build the collation table from.
+  * @exception ParseException thrown if rules are empty or a Runtime error
+  *            if collator can not be created.
+  * @stable ICU 2.4 
+  */
+  public RuleBasedCollator(String rules) throws ParseException
+  {
+    
+    if (rules.length() == 0)
+      throw new ParseException("Build rules empty.", 0);
+    m_collator_ = NativeCollation.openCollatorFromRules(rules,
+                              CollationAttribute.VALUE_OFF,
+                              CollationAttribute.VALUE_DEFAULT_STRENGTH);
+  }
+
+  /**
+  * RuleBasedCollator constructor. This takes the table rules and builds a 
+  * collation table out of them. Please see RuleBasedCollator class
+  * description for more details on the collation rule syntax.
+  * @param rules the collation rules to build the collation table from.
+  * @param strength collation strength
+  * @exception ParseException thrown if rules are empty or a Runtime error
+  *            if collator can not be created.
+  * @see #PRIMARY
+  * @see #SECONDARY
+  * @see #TERTIARY
+  * @see #QUATERNARY
+  * @see #IDENTICAL
+  * @stable ICU 2.4
+  */
+  public RuleBasedCollator(String rules, int strength) throws ParseException
+  {
+    if (rules.length() == 0)
+      throw new ParseException("Build rules empty.", 0);
+    if (!CollationAttribute.checkStrength(strength))
+      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+      
+    m_collator_ = NativeCollation.openCollatorFromRules(rules,
+                                CollationAttribute.VALUE_OFF,
+                                strength);
+  }
+
+  /**
+  * RuleBasedCollator constructor. This takes the table rules and builds a 
+  * collation table out of them. Please see RuleBasedCollator class
+  * description for more details on the collation rule syntax.
+  * <p>Note API change starting from release 2.4. Prior to release 2.4, the 
+  * normalizationmode argument values are from the class 
+  * com.ibm.icu4jni.text.Normalization. In 2.4, 
+  * the valid normalizationmode arguments for this API are 
+  * CollationAttribute.VALUE_ON and CollationAttribute.VALUE_OFF.
+  * </p>
+  * @param rules the collation rules to build the collation table from.
+  * @param strength collation strength
+  * @param normalizationmode normalization mode
+  * @exception IllegalArgumentException thrown when constructor error occurs
+  * @see #PRIMARY
+  * @see #SECONDARY
+  * @see #TERTIARY
+  * @see #QUATERNARY
+  * @see #IDENTICAL
+  * @see #CANONICAL_DECOMPOSITION
+  * @see #NO_DECOMPOSITION
+  * @stable ICU 2.4
+  */
+  public RuleBasedCollator(String rules, int normalizationmode, int strength)
+  {
+    if (!CollationAttribute.checkStrength(strength) || 
+        !CollationAttribute.checkNormalization(normalizationmode)) {
+      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+    }
+      
+    m_collator_ = NativeCollation.openCollatorFromRules(rules,
+                                          normalizationmode, strength);
+  }
+  
+  // public methods -----------------------------------------------
+  
+  /**
+  * Makes a complete copy of the current object.
+  * @return a copy of this object if data clone is a success, otherwise null
+  * @stable ICU 2.4 
+  */
+  public Object clone() 
+  {
+    RuleBasedCollator result = null;
+    int collatoraddress = NativeCollation.safeClone(m_collator_);
+    result = new RuleBasedCollator(collatoraddress);
+    return (Collator)result;
+  }
+                              
+  /**
+  * The comparison function compares the character data stored in two
+  * different strings. Returns information about whether a string is less 
+  * than, greater than or equal to another string.
+  * <p>Example of use:
+  * <br>
+  * <code>
+  *   Collator myCollation = Collator.createInstance(Locale::US);
+  *   myCollation.setStrength(CollationAttribute.VALUE_PRIMARY);
+  *   // result would be Collator.RESULT_EQUAL ("abc" == "ABC")
+  *   // (no primary difference between "abc" and "ABC")
+  *   int result = myCollation.compare("abc", "ABC",3);
+  *   myCollation.setStrength(CollationAttribute.VALUE_TERTIARY);
+  *   // result would be Collation::LESS (abc" &lt;&lt;&lt; "ABC")
+  *   // (with tertiary difference between "abc" and "ABC")
+  *   int result = myCollation.compare("abc", "ABC",3);
+  * </code>
+  * @param source The source string.
+  * @param target The target string.
+  * @return result of the comparison, Collator.RESULT_EQUAL, 
+  *         Collator.RESULT_GREATER or Collator.RESULT_LESS
+  * @stable ICU 2.4 
+  */
+  public int compare(String source, String target)
+  {
+    return NativeCollation.compare(m_collator_, source, target);
+  }
+                                               
+  /**
+  * Get the normalization mode for this object.
+  * The normalization mode influences how strings are compared.
+  * @see #CANONICAL_DECOMPOSITION
+  * @see #NO_DECOMPOSITION
+  * @stable ICU 2.4
+  */
+  public int getDecomposition()
+  {
+    return NativeCollation.getNormalization(m_collator_);
+  }
+
+  /**
+  * <p>Sets the decomposition mode of the Collator object on or off.
+  * If the decomposition mode is set to on, string would be decomposed into
+  * NFD format where necessary before sorting.</p>
+  * </p>
+  * @param decompositionmode the new decomposition mode
+  * @see #CANONICAL_DECOMPOSITION
+  * @see #NO_DECOMPOSITION
+  * @stable ICU 2.4
+  */
+  public void setDecomposition(int decompositionmode)
+  {
+    if (!CollationAttribute.checkNormalization(decompositionmode)) 
+      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+    NativeCollation.setAttribute(m_collator_, 
+                                 CollationAttribute.NORMALIZATION_MODE,
+                                 decompositionmode);
+  }
+
+  /**
+  * Determines the minimum strength that will be use in comparison or
+  * transformation.
+  * <p>
+  * E.g. with strength == CollationAttribute.VALUE_SECONDARY, the tertiary difference 
+  * is ignored
+  * </p>
+  * <p>
+  * E.g. with strength == PRIMARY, the secondary and tertiary difference are 
+  * ignored.
+  * </p>
+  * @return the current comparison level.
+  * @see #PRIMARY
+  * @see #SECONDARY
+  * @see #TERTIARY
+  * @see #QUATERNARY
+  * @see #IDENTICAL
+  * @stable ICU 2.4
+  */
+  public int getStrength()
+  {
+    return NativeCollation.getAttribute(m_collator_, 
+                                        CollationAttribute.STRENGTH);
+  }
+  
+  /**
+  * Sets the minimum strength to be used in comparison or transformation.
+  * <p>Example of use:
+  * <br>
+  * <code>
+  * Collator myCollation = Collator.createInstance(Locale::US);
+  * myCollation.setStrength(PRIMARY);
+  * // result will be "abc" == "ABC"
+  * // tertiary differences will be ignored
+  * int result = myCollation->compare("abc", "ABC");
+  * </code>
+  * @param strength the new comparison level.
+  * @exception IllegalArgumentException when argument does not belong to any collation strength 
+  *            mode or error occurs while setting data.
+  * @see #PRIMARY
+  * @see #SECONDARY
+  * @see #TERTIARY
+  * @see #QUATERNARY
+  * @see #IDENTICAL
+  * @stable ICU 2.4
+  */
+  public void setStrength(int strength)
+  {
+    if (!CollationAttribute.checkStrength(strength)) 
+      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+    NativeCollation.setAttribute(m_collator_, CollationAttribute.STRENGTH, 
+                                 strength);
+  }
+  
+  /**
+  * Sets the attribute to be used in comparison or transformation.
+  * <p>Example of use:
+  * <br>
+  * <code>
+  *  Collator myCollation = Collator.createInstance(Locale::US);
+  *  myCollation.setAttribute(CollationAttribute.CASE_LEVEL, 
+  *                           CollationAttribute.VALUE_ON);
+  *  int result = myCollation->compare("\\u30C3\\u30CF", 
+  *                                    "\\u30C4\\u30CF");
+  * // result will be Collator.RESULT_LESS.
+  * </code>
+  * @param type the attribute to be set from CollationAttribute
+  * @param value attribute value from CollationAttribute
+  * @stable ICU 2.4
+  */
+  public void setAttribute(int type, int value)
+  {
+    if (!CollationAttribute.checkAttribute(type, value))
+      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+    NativeCollation.setAttribute(m_collator_, type, value);
+  }
+  
+  /**
+  * Gets the attribute to be used in comparison or transformation.
+  * @param type the attribute to be set from CollationAttribute
+  * @return value attribute value from CollationAttribute
+  * @stable ICU 2.4 
+  */
+  public int getAttribute(int type)
+  {
+    if (!CollationAttribute.checkType(type))
+      throw ErrorCode.getException(ErrorCode.U_ILLEGAL_ARGUMENT_ERROR);
+    return NativeCollation.getAttribute(m_collator_, type);
+  }
+  
+  /**
+  * Get the sort key as an CollationKey object from the argument string.
+  * To retrieve sort key in terms of byte arrays, use the method as below<br>
+  * <br>
+  * <code>
+  * Collator collator = Collator.getInstance();
+  * byte[] array = collator.getSortKey(source);
+  * </code><br>
+  * Byte array result are zero-terminated and can be compared using 
+  * java.util.Arrays.equals();
+  * @param source string to be processed.
+  * @return the sort key
+  * @stable ICU 2.4 
+  */
+  public CollationKey getCollationKey(String source)
+  {
+    // BEGIN android-removed
+    // return new CollationKey(NativeCollation.getSortKey(m_collator_, source));
+    // END android-removed
+    // BEGIN android-added
+    if(source == null) {
+        return null;
+    }
+    byte[] key = NativeCollation.getSortKey(m_collator_, source);
+    if(key == null) {
+      return null;
+    }
+    return new CollationKey(key);
+    // END android-added
+  }
+  
+  /**
+  * Get a sort key for the argument string
+  * Sort keys may be compared using java.util.Arrays.equals
+  * @param source string for key to be generated
+  * @return sort key
+  * @stable ICU 2.4 
+  */
+  public byte[] getSortKey(String source)
+  {
+    return NativeCollation.getSortKey(m_collator_, source);
+  }
+  
+  /**
+  * Get the collation rules of this Collation object
+  * The rules will follow the rule syntax.
+  * @return collation rules.
+  * @stable ICU 2.4 
+  */
+  public String getRules()
+  {
+    return NativeCollation.getRules(m_collator_);
+  }
+  
+  /** 
+  * Create a CollationElementIterator object that will iterator over the 
+  * elements in a string, using the collation rules defined in this 
+  * RuleBasedCollator
+  * @param source string to iterate over
+  * @return address of C collationelement
+  * @exception IllegalArgumentException thrown when error occurs
+  * @stable ICU 2.4 
+  */
+  public CollationElementIterator getCollationElementIterator(String source)
+  {
+    CollationElementIterator result = new CollationElementIterator(
+         NativeCollation.getCollationElementIterator(m_collator_, source));
+    // result.setOwnCollationElementIterator(true);
+    return result;
+  }
+  
+  // BEGIN android-added
+  /** 
+  * Create a CollationElementIterator object that will iterator over the 
+  * elements in a string, using the collation rules defined in this 
+  * RuleBasedCollator
+  * @param source string to iterate over
+  * @return address of C collationelement
+  * @exception IllegalArgumentException thrown when error occurs
+  * @stable ICU 2.4 
+  */
+  public CollationElementIterator getCollationElementIterator(
+          CharacterIterator source)
+  {
+    CollationElementIterator result = new CollationElementIterator(
+         NativeCollation.getCollationElementIterator(m_collator_, 
+                 source.toString()));
+    // result.setOwnCollationElementIterator(true);
+    return result;
+  }
+  // END android-added
+  
+  /**
+  * Returns a hash of this collation object
+  * Note this method is not complete, it only returns 0 at the moment.
+  * @return hash of this collation object
+  * @stable ICU 2.4 
+  */
+  public int hashCode()
+  {
+    // since rules do not change once it is created, we can cache the hash
+    if (m_hashcode_ == 0) {
+      m_hashcode_ = NativeCollation.hashCode(m_collator_);
+      if (m_hashcode_ == 0)
+        m_hashcode_ = 1;
+    }
+    return m_hashcode_;
+  }
+  
+  /**
+  * Checks if argument object is equals to this object.
+  * @param target object
+  * @return true if source is equivalent to target, false otherwise 
+  * @stable ICU 2.4 
+  */
+  public boolean equals(Object target)
+  {
+    if (this == target) 
+      return true;
+    if (target == null) 
+      return false;
+    if (getClass() != target.getClass()) 
+      return false;
+    
+    RuleBasedCollator tgtcoll = (RuleBasedCollator)target;
+    return getRules().equals(tgtcoll.getRules()) && 
+           getStrength() == tgtcoll.getStrength() && 
+           getDecomposition() == tgtcoll.getDecomposition();
+  }
+  
+  // package constructor ----------------------------------------
+  
+  /**
+  * RuleBasedCollator default constructor. This constructor takes the default 
+  * locale. The only caller of this class should be Collator.getInstance(). 
+  * Current implementation createInstance() returns a RuleBasedCollator(Locale) 
+  * instance. The RuleBasedCollator will be created in the following order,
+  * <ul>
+  * <li> Data from argument locale resource bundle if found, otherwise
+  * <li> Data from parent locale resource bundle of arguemtn locale if found,
+  *      otherwise
+  * <li> Data from built-in default collation rules if found, other
+  * <li> null is returned
+  * </ul>
+  */
+  RuleBasedCollator()
+  {
+    m_collator_ = NativeCollation.openCollator();
+  }
+
+  /**
+  * RuleBasedCollator constructor. This constructor takes a locale. The 
+  * only caller of this class should be Collator.createInstance(). 
+  * Current implementation createInstance() returns a RuleBasedCollator(Locale) 
+  * instance. The RuleBasedCollator will be created in the following order,
+  * <ul>
+  * <li> Data from argument locale resource bundle if found, otherwise
+  * <li> Data from parent locale resource bundle of arguemtn locale if found,
+  *      otherwise
+  * <li> Data from built-in default collation rules if found, other
+  * <li> null is returned
+  * </ul>
+  * @param locale locale used
+  */
+  RuleBasedCollator(Locale locale)
+  {
+    if (locale == null) {
+      m_collator_ = NativeCollation.openCollator();
+    }
+    else {
+      m_collator_ = NativeCollation.openCollator(locale.toString());
+    }
+  }
+  
+  // protected methods --------------------------------------------
+  
+  /**
+  * Garbage collection.
+  * Close C collator and reclaim memory.
+  */
+  protected void finalize()
+  {
+    NativeCollation.closeCollator(m_collator_);
+  }
+  
+  // private data members -----------------------------------------
+  
+  /**
+  * C collator
+  */
+  private int m_collator_;
+  
+  /**
+  * Hash code for rules
+  */
+  private int m_hashcode_ = 0;
+  
+  // private constructor -----------------------------------------
+  
+  /**
+  * Private use constructor.
+  * Does not create any instance of the C collator. Accepts argument as the
+  * C collator for new instance.
+  * @param collatoraddress address of C collator
+  */
+  private RuleBasedCollator(int collatoraddress)
+  {
+    m_collator_ = collatoraddress;
+  }
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedNumberFormat.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedNumberFormat.java
new file mode 100644
index 0000000..58ddf0e
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/RuleBasedNumberFormat.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.text;
+
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+public class RuleBasedNumberFormat extends NumberFormat {
+
+    /**
+     * Enum of predefined RBNF types.
+     */
+    public enum RBNFType {
+        /**
+         * This creates a spellout instance of RBNF.
+         * It formats numbers into textual representation:
+         * 15 -> 'fifteen' or 15.15 -> 'fifteen point one five'
+         *  and it can parse words into numbers: 'twenty' -> 20
+         */
+        SPELLOUT(0),
+        /**
+         * This creates an ordinal instance of RBNF.
+         * It formats numbers into an ordinal text representation:
+         * 15 -> '15th' and by parsing it also works in the other direction.
+         */
+        ORDINAL(1),
+        /**
+         * This creates instance of RBNF that allows to format numbers into time
+         * values: 15 -> '15 sec.' and by parsing it also works in the other
+         * direction.
+         */
+        DURATION(2);
+        
+        int type;
+        
+        RBNFType(int t) {
+            type = t;
+        }
+        
+        int getType() {
+            return type;
+        }
+    }
+    
+    @Override
+    protected void finalize(){
+        close();
+    }
+    
+    private int addr = 0;
+
+    /**
+     * Open a new rule based number format of selected type for the 
+     * default location
+     * 
+     * @param type the type of rule based number format
+     */
+    public void open(RBNFType type) {
+        this.addr = openRBNFImpl(type.getType(),
+                Locale.getDefault().toString());
+    }
+
+    /**
+     * Open a new rule based number format of selected type for the 
+     * given location
+     * 
+     * @param type the type of rule based number format
+     * @param locale the locale to use for this rule based number format
+     */
+    public void open(RBNFType type, Locale locale) {
+        this.addr = openRBNFImpl(type.getType(),
+                locale.toString());
+    }
+    
+    private static native int openRBNFImpl(int type, String loc);
+
+    /**
+     * Open a new rule based number format for the 
+     * default location. The rule passed to the method has to be of the form
+     * described in the ibm icu documentation for RuleBasedNumberFormat.
+     * 
+     * @param rule the rule for the rule based number format
+     */
+    public void open(String rule) {
+        this.addr = openRBNFImpl(rule, Locale.getDefault().toString());
+    }
+
+    /**
+     * Open a new rule based number format for the 
+     * given location. The rule passed to the method has to be of the form
+     * described in the ibm icu documentation for RuleBasedNumberFormat.
+     * 
+     * @param rule the rule for the rule based number format
+     * @param locale the locale to use for this rule based number format
+     */
+    public void open(String rule, Locale locale) {
+        this.addr = openRBNFImpl(rule, locale.toString());
+    }
+    
+    private static native int openRBNFImpl(String rule, String loc);
+    
+    /**
+     * close a RuleBasedNumberFormat
+     */
+    public void close() {
+        if(this.addr != 0) {
+            closeRBNFImpl(this.addr);
+            this.addr = 0;
+        }
+    }
+    
+    private static native void closeRBNFImpl(int addr); 
+    
+    @Override
+    public StringBuffer format(long value, StringBuffer buffer, FieldPosition field) {
+
+        if(buffer == null) {
+            throw new NullPointerException();
+        }
+        
+        String fieldType = null;
+        
+        if(field != null) {
+            fieldType = getFieldType(field.getFieldAttribute());
+        }
+        
+        String result = formatRBNFImpl(this.addr, value, field, 
+                fieldType, null);
+        
+        buffer.append(result.toCharArray(), 0, result.length());
+        
+        return buffer;
+    }
+    
+    private static native String formatRBNFImpl(int addr, long value, 
+            FieldPosition field, String fieldType, StringBuffer buffer);
+
+    @Override
+    public StringBuffer format(double value, StringBuffer buffer, FieldPosition field) {
+
+        if(buffer == null) {
+            throw new NullPointerException();
+        }
+        
+        String fieldType = null;
+        
+        if(field != null) {
+            fieldType = getFieldType(field.getFieldAttribute());
+        }
+        
+        String result = formatRBNFImpl(this.addr, value, field, 
+                fieldType, null);
+        
+        buffer.append(result.toCharArray(), 0, result.length());
+        
+        return buffer;
+    }
+    
+    private static native String formatRBNFImpl(int addr, double value, 
+            FieldPosition field, String fieldType, StringBuffer buffer);
+
+    @Override
+    public Number parse(String string, ParsePosition position) {
+        return parseRBNFImpl(this.addr, string, position, false);
+    }
+    
+    /**
+     * This method has the same functionality 
+     * as {@link #parse(String, ParsePosition)}
+     * But it uses lenient parsing. This means it also accepts strings that
+     * differ from the correct writing (e.g. case or umlaut differences).
+     * 
+     * @param string the string to parse
+     * @param position the ParsePosition, updated on return with the index 
+     *        following the parsed text, or on error the index is unchanged and 
+     *        the error index is set to the index where the error occurred
+     * @return the Number resulting from the parse, or null if there is an error
+     */
+    public Number parseLenient(String string, ParsePosition position) {
+        return parseRBNFImpl(this.addr, string, position, true);
+    }
+    
+    static native Number parseRBNFImpl(int addr, String string, ParsePosition position, boolean lenient);
+    
+    
+    static private String getFieldType(Format.Field field) {
+        if(field == null) {
+            return null;
+        }
+        if(field.equals(NumberFormat.Field.SIGN)) {
+            return "sign";
+        }
+        if(field.equals(NumberFormat.Field.INTEGER)) {
+            return "integer";
+        }
+        if(field.equals(NumberFormat.Field.FRACTION)) {
+            return "fraction";
+        }
+        if(field.equals(NumberFormat.Field.EXPONENT)) {
+            return "exponent";
+        }
+        if(field.equals(NumberFormat.Field.EXPONENT_SIGN)) {
+            return "exponent_sign";
+        }
+        if(field.equals(NumberFormat.Field.EXPONENT_SYMBOL)) {
+            return "exponent_symbol";
+        }
+        if(field.equals(NumberFormat.Field.CURRENCY)) {
+            return "currency";
+        }
+        if(field.equals(NumberFormat.Field.GROUPING_SEPARATOR)) {
+            return "grouping_separator";
+        }
+        if(field.equals(NumberFormat.Field.DECIMAL_SEPARATOR)) {
+            return "decimal_separator";
+        }
+        if(field.equals(NumberFormat.Field.PERCENT)) {
+            return "percent";
+        }
+        if(field.equals(NumberFormat.Field.PERMILLE)) {
+            return "permille";
+        }
+        return null;
+    }
+}
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java b/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
new file mode 100644
index 0000000..85530ac
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.ibm.icu4jni.util;
+
+import java.util.Enumeration;
+import java.util.ListResourceBundle;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.TimeZone;
+import java.util.logging.Logger;
+
+/**
+ * Helper class that delivers ResourceBundle instances expected by Harmony, but
+ * with the data taken from ICU's database. This approach has a couple of
+ * advantages:
+ * <ol>
+ * <li> We have less classes in the overall system, since we use different
+ * instances for different ResourceBundles.
+ * <li> We don't have these classes that consists of monstrous static arrays
+ * with anymore.
+ * <li> We have control over which values we load at which time or even cache
+ * for later use.
+ * <li> There is only one central place left in the system where I18N data needs
+ * to be configured, namely ICU.
+ * </ol>
+ * Since we're mimicking the original Harmony ResourceBundle structures, most of
+ * the Harmony code can stay the same. We basically just need to change the
+ * ResourceBundle instantiation. Only the special case of the Locale bundles
+ * needs some more tweaking, since we don't want to keep several hundred
+ * timezone names in memory.
+ */
+public class Resources {
+
+    /**
+     * Cache for ISO language names.
+     */
+    private static String[] isoLanguages = null;
+
+    /**
+     * Cache for ISO country names.
+     */
+    private static String[] isoCountries = null;
+
+    /**
+     * Available locales cache.
+     */
+    private static String[] availableLocales = null;
+
+    /**
+     * Available timezones cache.
+     */
+    private static String[] availableTimezones = null;
+
+    /**
+     * Creates ResourceBundle instance and fills it with ICU data.
+     * 
+     * @param bundleName The name of the requested Harmony resource bundle,
+     *            excluding the package name.
+     * @param locale The locale to use for the resources. A null value denotes
+     *            the default locale as configured in Java.
+     * @return The new ResourceBundle, or null, if no ResourceBundle was
+     *         created.
+     */
+    public static ResourceBundle getInstance(String bundleName, String locale) {
+        if (locale == null) {
+            locale = java.util.Locale.getDefault().toString();
+        }
+
+        if (bundleName.startsWith("Locale")) {
+            return new Locale(locale);
+        } else if (bundleName.startsWith("Country")) {
+            return new Country(locale);
+        } else if (bundleName.startsWith("Currency")) {
+            return new Currency(locale);
+        } else if (bundleName.startsWith("Language")) {
+            return new Language(locale);
+        } else if (bundleName.startsWith("Variant")) {
+            return new Variant(locale);
+        } else if (bundleName.equals("ISO3Countries")) {
+            return new ISO3Countries();
+        } else if (bundleName.equals("ISO3Languages")) {
+            return new ISO3Languages();
+        } else if (bundleName.equals("ISO4CurrenciesToDigits")) {
+            return new ISO4CurrenciesToDigits();
+        } else if (bundleName.equals("ISO4Currencies")) {
+            return new ISO4Currencies();
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns an array of ISO language names (two-letter codes), fetched either
+     * from ICU's database or from our memory cache.
+     * 
+     * @return The array.
+     */
+    public static String[] getISOLanguages() {
+        if (isoLanguages == null) {
+            isoLanguages = getISOLanguagesNative();
+        }
+
+        return isoLanguages;
+    }
+
+    /**
+     * Returns an array of ISO country names (two-letter codes), fetched either
+     * from ICU's database or from our memory cache.
+     * 
+     * @return The array.
+     */
+    public static String[] getISOCountries() {
+        if (isoCountries == null) {
+            isoCountries = getISOCountriesNative();
+        }
+
+        return isoCountries;
+    }
+
+    /**
+     * Returns an array of names of locales that are available in the system,
+     * fetched either from ICU's database or from our memory cache.
+     * 
+     * @return The array.
+     */
+    public static String[] getAvailableLocales() {
+        if (availableLocales == null) {
+            availableLocales = getAvailableLocalesNative();
+        }
+
+        return availableLocales;
+    }
+
+    /**
+     * Returns an array of names of timezones that are available in the system,
+     * fetched either from the TimeZone class or from our memory cache.
+     * 
+     * @return The array.
+     */
+    public static String[] getKnownTimezones() {
+        // TODO Drop the Linux ZoneInfo stuff in favor of ICU.
+        if (availableTimezones == null) {
+            availableTimezones = TimeZone.getAvailableIDs();
+        }
+
+        return availableTimezones;
+    }
+
+    /**
+     * Returns the display name for the given time zone using the given locale.
+     * 
+     * @param id The time zone ID, for example "Europe/Berlin"
+     * @param isDST Indicates whether daylight savings is in use
+     * @param style The style, 0 for long, 1 for short
+     * @param locale The locale name, for example "en_US".
+     * @return The desired display name
+     */
+    public static String getDisplayTimeZone(String id, boolean isDST, int style, String locale) {
+        return getDisplayTimeZoneNative(id, isDST, style, locale);
+    }
+
+    /**
+     * Gets the name of the default locale.
+     */
+    private static String getDefaultLocaleName() {
+        return java.util.Locale.getDefault().toString();
+    }
+    
+    /**
+     * Name of default locale at the time this class was initialized.
+     */
+    private static final String initialLocale = getDefaultLocaleName();
+
+    /**
+     * Names of time zones for the default locale.
+     */
+    private static String[][] defaultTimezoneNames = null;
+
+    /**
+     * Creates array of time zone names for the given locale. This method takes
+     * about 2s to run on a 400mhz ARM11.
+     */
+    private static String[][] createTimeZoneNamesFor(String locale) {
+        long start = System.currentTimeMillis();
+
+        /*
+         * The following code is optimized for fast native response (the time a
+         * method call can be in native code is limited). It prepares an empty
+         * array to keep native code from having to create new Java objects. It
+         * also fill in the time zone IDs to speed things up a bit. There's one
+         * array for each time zone name type. (standard/long, standard/short,
+         * daylight/long, daylight/short) The native method that fetches these
+         * strings is faster if it can do all entries of one type, before having
+         * to change to the next type. That's why the array passed down to
+         * native has 5 entries, each providing space for all time zone names of
+         * one type. Likely this access to the fields is much faster in the
+         * native code because there's less array access overhead.
+         */
+        String[][] arrayToFill = new String[5][];
+        arrayToFill[0] = getKnownTimezones();
+        arrayToFill[1] = new String[availableTimezones.length];
+        arrayToFill[2] = new String[availableTimezones.length];
+        arrayToFill[3] = new String[availableTimezones.length];
+        arrayToFill[4] = new String[availableTimezones.length];
+
+        /*
+         * Fill in the zone names in native.
+         */
+        getTimeZonesNative(arrayToFill, locale);
+
+        /*
+         * Finally we need to reorder the entries so we get the expected result.
+         */
+        String[][] result = new String[availableTimezones.length][5];
+        for (int i = 0; i < availableTimezones.length; i++) {
+            result[i][0] = arrayToFill[0][i];
+            result[i][1] = arrayToFill[1][i];
+            result[i][2] = arrayToFill[2][i];
+            result[i][3] = arrayToFill[3][i];
+            result[i][4] = arrayToFill[4][i];
+        }
+
+        Logger.getLogger(Resources.class.getSimpleName()).info(
+                "Loaded time zone names for " + locale + " in "
+                + (System.currentTimeMillis() - start) + "ms.");
+
+        return result;
+    }
+
+    /**
+     * Returns the display names for all given timezones using the given locale.
+     * 
+     * @return An array of time zone strings. Each row represents one time zone.
+     *         The first columns holds the ID of the time zone, for example
+     *         "Europe/Berlin". The other columns then hold for each row the
+     *         four time zone names with and without daylight savings and in
+     *         long and short format. It's exactly the array layout required by
+     *         the TomeZone class.
+     */
+    public static String[][] getDisplayTimeZones(String locale) {
+        // Note: Defer loading DefaultTimeZones as long as possible.
+
+        String defaultLocaleName = getDefaultLocaleName();
+        if (locale == null) {
+            locale = defaultLocaleName;
+        }
+
+        // If locale == default and the default locale hasn't changed since
+        // DefaultTimeZones loaded, return the cached names.
+        // TODO: We should force a reboot if the default locale changes.
+        if (defaultLocaleName.equals(locale)
+                && initialLocale.equals(defaultLocaleName)) {
+            if (defaultTimezoneNames == null) {
+                defaultTimezoneNames = createTimeZoneNamesFor(locale);
+            }
+            return defaultTimezoneNames;
+        }
+        
+        return createTimeZoneNamesFor(locale);
+    }
+
+    // --- Specialized ResourceBundle subclasses ------------------------------
+
+    /**
+     * Internal ResourceBundle mimicking the Harmony "ISO3Countries" bundle.
+     * Keys are the two-letter ISO country codes. Values are the three-letter
+     * ISO country abbreviations. An example entry is "US"->"USA".
+     */
+    private static final class ISO3Countries extends ResourceBundle {
+
+        @Override
+        public Enumeration<String> getKeys() {
+            // Won't get used
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected Object handleGetObject(String key) {
+            return getISO3CountryNative(key);
+        }
+
+    }
+
+    /**
+     * Internal ResourceBundle mimicking the Harmony "ISO3Languages" bundle.
+     * Keys are the two-letter ISO language codes. Values are the three-letter
+     * ISO language abbreviations. An example entry is "EN"->"ENG".
+     */
+    private static final class ISO3Languages extends ResourceBundle {
+
+        @Override
+        public Enumeration<String> getKeys() {
+            // Won't get used
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected Object handleGetObject(String key) {
+            return getISO3LanguageNative(key);
+        }
+
+    }
+
+    /**
+     * Internal ResourceBundle mimicking the Harmony "ISO4Currencies" bundle.
+     * Keys are the two-letter ISO language codes. Values are the three-letter
+     * ISO currency abbreviations. An example entry is "US"->"USD".
+     */
+    private static final class ISO4Currencies extends ResourceBundle {
+
+        @Override
+        public Enumeration<String> getKeys() {
+            // Won't get used
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected Object handleGetObject(String key) {
+            return getCurrencyCodeNative(key);
+        }
+
+    }
+
+    /**
+     * Internal ResourceBundle mimicking the Harmony "ISO4CurrenciesToDigits"
+     * bundle. Keys are the three-letter ISO currency codes. Values are strings
+     * containing the number of fraction digits to use for the currency. An
+     * example entry is "USD"->"2".
+     */
+    private static final class ISO4CurrenciesToDigits extends ResourceBundle {
+
+        @Override
+        public Enumeration<String> getKeys() {
+            // Won't get used
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected Object handleGetObject(String key) {
+            // In some places the triple-x code is used as the fall back
+            // currency. The harmony package returned -1 for this requested
+            // currency.
+            if ("XXX".equals(key)) {
+                return "-1";
+            }
+            int res = getFractionDigitsNative(key);
+            if(res < 0) {
+                throw new MissingResourceException("couldn't find resource.", 
+                        ISO4CurrenciesToDigits.class.getName(), key);
+            }
+            return "" + res;
+        }
+
+    }
+
+    /**
+     * Internal ResourceBundle mimicking the Harmony "Country_*" bundles. Keys
+     * are the two-letter ISO country codes. Values are the printable country
+     * names in terms of the specified locale. An example entry is "US"->"United
+     * States".
+     */
+    private static final class Country extends ResourceBundle {
+        private String locale;
+
+        public Country(String locale) {
+            super();
+            this.locale = locale;
+        }
+
+        @Override
+        public Enumeration<String> getKeys() {
+            // Won't get used
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected Object handleGetObject(String key) {
+            return getDisplayCountryNative(key, locale);
+        }
+
+    }
+
+    /**
+     * Internal ResourceBundle mimicking the Harmony "Currency_*" bundles. Keys
+     * are the three-letter ISO currency codes. Values are the printable
+     * currency names in terms of the specified locale. An example entry is
+     * "USD"->"$" (for inside the US) and "USD->"US$" (for outside the US).
+     */
+    private static final class Currency extends ResourceBundle {
+
+        private String locale;
+
+        public Currency(String locale) {
+            super();
+            this.locale = locale;
+        }
+
+        @Override
+        public Enumeration<String> getKeys() {
+            // Won't get used
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected Object handleGetObject(String key) {
+            return getCurrencySymbolNative(locale, key);
+        }
+
+    }
+
+    /**
+     * Internal ResourceBundle mimicking the Harmony "Language_*" bundles. Keys
+     * are the two-letter ISO language codes. Values are the printable language
+     * names in terms of the specified locale. An example entry is
+     * "en"->"English".
+     */
+    private static final class Language extends ResourceBundle {
+        private String locale;
+
+        public Language(String locale) {
+            super();
+            this.locale = locale;
+        }
+
+        @Override
+        public Enumeration<String> getKeys() {
+            // Won't get used
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected Object handleGetObject(String key) {
+            return getDisplayLanguageNative(key, locale);
+        }
+
+    }
+
+    /**
+     * Internal ResourceBundle mimicking the Harmony "Variant_*" bundles. Keys
+     * are a fixed set of variants codes known to Harmony. Values are the
+     * printable variant names in terms of the specified locale. An example
+     * entry is "EURO"->"Euro".
+     */
+    private static final class Variant extends ResourceBundle {
+
+        private String locale;
+
+        public Variant(String locale) {
+            super();
+            this.locale = locale;
+        }
+
+        @Override
+        public Enumeration<String> getKeys() {
+            // Won't get used
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected Object handleGetObject(String key) {
+            return getDisplayVariantNative(key, locale);
+        }
+
+    }
+
+    /**
+     * Internal ResourceBundle mimicking the Harmony "Locale_*" bundles. This is
+     * clearly the most complex case, because the content covers a wide range of
+     * data items, with values even being arrays in some cases. Note we are
+     * cheating with the "timezones" entry, since we normally don't want to
+     * waste our precious RAM on several thousand of these Strings.
+     */
+    private static final class Locale extends ListResourceBundle {
+
+        private String locale;
+
+        public Locale(String locale) {
+            super();
+            this.locale = locale;
+        }
+
+        @Override
+        protected Object[][] getContents() {
+            return getContentImpl(locale, false);
+        }
+
+    }
+
+    // --- Native methods accessing ICU's database ----------------------------
+
+    private static native int getFractionDigitsNative(String currencyCode);
+
+    private static native String getCurrencyCodeNative(String locale);
+
+    private static native String getCurrencySymbolNative(String locale, String currencyCode);
+
+    private static native String getDisplayCountryNative(String countryCode, String locale);
+
+    private static native String getDisplayLanguageNative(String languageCode, String locale);
+
+    private static native String getDisplayVariantNative(String variantCode, String locale);
+
+    private static native String getISO3CountryNative(String locale);
+
+    private static native String getISO3LanguageNative(String locale);
+
+    private static native String[] getAvailableLocalesNative();
+
+    private static native String[] getISOLanguagesNative();
+
+    private static native String[] getISOCountriesNative();
+
+    private static native void getTimeZonesNative(String[][] arrayToFill, String locale);
+
+    private static native String getDisplayTimeZoneNative(String id, boolean isDST, int style,
+            String locale);
+
+    private static native Object[][] getContentImpl(String locale, boolean needsTimeZones);
+}
diff --git a/libcore/icu/src/main/native/BidiWrapperInterface.c b/libcore/icu/src/main/native/BidiWrapperInterface.c
new file mode 100644
index 0000000..2c6b3cd
--- /dev/null
+++ b/libcore/icu/src/main/native/BidiWrapperInterface.c
@@ -0,0 +1,253 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+#include <stdlib.h>
+#include <unicode/ubidi.h>
+#include <string.h>
+#include "BidiWrapperInterface.h"
+
+typedef struct {
+    UBiDi *pBiDi;
+    void *embeddingLevels;
+} BiDiData;
+
+void check_fail (JNIEnv * env, int err);
+
+JNIEXPORT jlong JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1open
+  (JNIEnv * env, jclass clazz)
+{
+  BiDiData *data = (BiDiData *)malloc(sizeof(BiDiData)); 
+  (*data).pBiDi = ubidi_open ();
+  (*data).embeddingLevels = NULL;
+  return (jlong) (data);
+}
+
+JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1close
+  (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+  BiDiData *data = (BiDiData *)pBiDi;
+
+  ubidi_close ((*data).pBiDi);
+  
+  if ((*data).embeddingLevels != NULL)
+    free((*data).embeddingLevels);
+    free(data);
+}
+
+JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setPara
+  (JNIEnv * env, jclass clazz, jlong pBiDi, jcharArray text, jint length,
+   jbyte paraLevel, jbyteArray embeddingLevels)
+{
+  UErrorCode err = 0;
+  jchar *_text = NULL;
+  BiDiData *data = (BiDiData *)pBiDi;
+  /* Remembering old embedding levels */
+  void *embLvls = (*data).embeddingLevels;
+  
+  _text = (*env)->GetCharArrayElements (env, text, NULL);
+
+  if (embeddingLevels != NULL)
+    {        
+        jbyte *el = (*env)->GetByteArrayElements (env, embeddingLevels, NULL);
+        (*data).embeddingLevels = malloc(length);
+        memcpy(((*data).embeddingLevels), el, length);
+        (*env)->ReleaseByteArrayElements (env, embeddingLevels, el, 0);
+    } else
+    {
+        (*data).embeddingLevels = NULL;
+    }
+
+  ubidi_setPara ((*data).pBiDi, _text, length, paraLevel,
+                 ((*data).embeddingLevels), &err);
+  check_fail (env, err);
+
+  /* Freeing old embedding levels */
+  if (embLvls != NULL) {
+    free(embLvls);
+  }
+
+  (*env)->ReleaseCharArrayElements (env, text, _text, 0);
+}
+
+JNIEXPORT jlong JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setLine
+  (JNIEnv * env, jclass clazz, jlong pBiDi, jint start, jint limit)
+{
+  UErrorCode err = 0;
+  BiDiData *data = (BiDiData *)pBiDi;
+  BiDiData *lineData = (BiDiData *) malloc(sizeof(BiDiData));
+  (*lineData).embeddingLevels = NULL;
+
+  (*lineData).pBiDi = ubidi_openSized (limit - start, 0, &err);
+  check_fail (env, err);
+
+  ubidi_setLine ((*data).pBiDi, start, limit, (*lineData).pBiDi,
+                 &err);
+  check_fail (env, err);
+
+  return (jlong) lineData;
+}
+
+JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getDirection
+  (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+  BiDiData *data = (BiDiData *)pBiDi;
+  return ubidi_getDirection ((*data).pBiDi);
+}
+
+JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLength
+  (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+  BiDiData *data = (BiDiData *)pBiDi;
+  return ubidi_getLength ((*data).pBiDi);
+}
+
+JNIEXPORT jbyte JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getParaLevel
+  (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+  BiDiData *data = (BiDiData *)pBiDi;
+  return ubidi_getParaLevel ((*data).pBiDi);
+}
+
+JNIEXPORT jbyteArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLevels
+  (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+  UErrorCode err = 0;
+  const UBiDiLevel *levels = NULL;
+  jbyteArray result = NULL;
+  int len = 0;
+  BiDiData *data = (BiDiData *)pBiDi;
+
+  levels = ubidi_getLevels ((*data).pBiDi, &err);
+  check_fail (env, err);
+
+  len = ubidi_getLength ((*data).pBiDi);
+  result = (*env)->NewByteArray (env, len);
+  (*env)->SetByteArrayRegion (env, result, 0, len, (jbyte *) levels);
+
+  return result;
+}
+
+JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1countRuns
+  (JNIEnv * env, jclass clazz, jlong pBiDi)
+{
+  UErrorCode err = 0;
+  BiDiData *data = (BiDiData *)pBiDi;
+
+  int count = ubidi_countRuns ((*data).pBiDi, &err);
+  check_fail (env, err);
+
+  return count;
+}
+
+JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getRuns
+  (JNIEnv * env, jclass clz, jlong pBiDi)
+{
+  int runCount = 0;
+  int start = 0;
+  int limit = 0;
+  int i = 0;
+  UBiDiLevel level = 0;
+  jclass run_clazz = 0;
+  jmethodID initID = 0;
+  jobject run = 0;
+  jobjectArray runs;
+  UErrorCode err = 0;
+  BiDiData *data = (BiDiData *)pBiDi;
+
+  run_clazz = (*env)->FindClass (env, "org/apache/harmony/text/BidiRun");
+  initID = (*env)->GetMethodID (env, run_clazz, "<init>", "(III)V");
+
+  runCount = ubidi_countRuns ((*data).pBiDi, &err);
+  check_fail (env, err);
+  
+  runs = (*env)->NewObjectArray(env, runCount,run_clazz, NULL);  
+  for (i = 0; i < runCount; i++) {
+      ubidi_getLogicalRun((*data).pBiDi, start, &limit, &level);
+      run = (*env)->NewObject (env, run_clazz, initID, start, limit, level);
+      (*env)->SetObjectArrayElement(env, runs, i, run);
+      start = limit;
+  }
+  return runs;
+}
+
+void
+check_fail (JNIEnv * env, int err)
+{
+  char message[] = "ICU Internal Error:                     ";
+
+  if (U_FAILURE (err))
+    {
+      sprintf (message, "ICU Internal Error: %d", err);
+      jniThrowException(env, "java/lang/RuntimeException",
+                              message);
+    }
+}
+
+JNIEXPORT jintArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1reorderVisual
+  (JNIEnv * env, jclass clazz, jbyteArray levels, jint length)
+{
+  UBiDiLevel *local_levels = 0;
+  int *local_indexMap = 0;
+  jintArray result = 0;
+
+  local_indexMap = (int *) malloc(sizeof (int) * length);
+  local_levels = (*env)->GetByteArrayElements (env, levels, NULL);
+
+  ubidi_reorderVisual (local_levels, length, local_indexMap);
+
+  result = (*env)->NewIntArray (env, length);
+  (*env)->SetIntArrayRegion (env, result, 0, length, (jint *) local_indexMap);
+
+  free(local_indexMap);
+  (*env)->ReleaseByteArrayElements (env, levels, local_levels, 0);
+
+  return result;
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+    /* NAME                , SIGNATURE              ,       FUNCPTR */
+    { "ubidi_open"        , "()J"                                  ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1open          },
+    { "ubidi_close"        , "(J)V"                                 ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1close         },
+    { "ubidi_setPara"      , "(J[CIB[B)V"                           ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1setPara       },
+    { "ubidi_setLine"      , "(JII)J"                               ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1setLine       },
+    { "ubidi_getDirection" , "(J)I"                                 ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1getDirection  },
+    { "ubidi_getLength"    , "(J)I"                                 ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLength     },
+    { "ubidi_getParaLevel" , "(J)B"                                 ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1getParaLevel  },
+    { "ubidi_getLevels"    , "(J)[B"                                ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLevels     },
+    { "ubidi_countRuns"    , "(J)I"                                 ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1countRuns     },
+    { "ubidi_getRuns"      , "(J)[Lorg/apache/harmony/text/BidiRun;",
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1getRuns       },
+    { "ubidi_reorderVisual", "([BI)[I"                              ,
+        Java_org_apache_harmony_text_BidiWrapper_ubidi_1reorderVisual },
+};
+int register_org_apache_harmony_text_BidiWrapper(JNIEnv *env)
+{
+    return jniRegisterNativeMethods(env, "org/apache/harmony/text/BidiWrapper",
+                gMethods, NELEM(gMethods));
+}
diff --git a/libcore/icu/src/main/native/BidiWrapperInterface.h b/libcore/icu/src/main/native/BidiWrapperInterface.h
new file mode 100644
index 0000000..c73597e
--- /dev/null
+++ b/libcore/icu/src/main/native/BidiWrapperInterface.h
@@ -0,0 +1,132 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+#include <JNIHelp.h>
+/* Header for class org_apache_harmony_text_BidiWrapper */
+
+#if !defined(_Included_org_apache_harmony_text_BidiWrapper)
+#define _Included_org_apache_harmony_text_BidiWrapper
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_DEFAULT_LTR
+#define org_apache_harmony_text_BidiWrapper_UBIDI_DEFAULT_LTR 254L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_DEFAULT_RTL
+#define org_apache_harmony_text_BidiWrapper_UBIDI_DEFAULT_RTL 255L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_MAX_EXPLICIT_LEVEL
+#define org_apache_harmony_text_BidiWrapper_UBIDI_MAX_EXPLICIT_LEVEL 61L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_LEVEL_OVERRIDE
+#define org_apache_harmony_text_BidiWrapper_UBIDI_LEVEL_OVERRIDE 128L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_KEEP_BASE_COMBINING
+#define org_apache_harmony_text_BidiWrapper_UBIDI_KEEP_BASE_COMBINING 1L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_DO_MIRRORING
+#define org_apache_harmony_text_BidiWrapper_UBIDI_DO_MIRRORING 2L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_INSERT_LRM_FOR_NUMERIC
+#define org_apache_harmony_text_BidiWrapper_UBIDI_INSERT_LRM_FOR_NUMERIC 4L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_REMOVE_BIDI_CONTROLS
+#define org_apache_harmony_text_BidiWrapper_UBIDI_REMOVE_BIDI_CONTROLS 8L
+#undef org_apache_harmony_text_BidiWrapper_UBIDI_OUTPUT_REVERSE
+#define org_apache_harmony_text_BidiWrapper_UBIDI_OUTPUT_REVERSE 16L
+#undef org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_LTR
+#define org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_LTR 0L
+#undef org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_RTL
+#define org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_RTL 1L
+#undef org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_MIXED
+#define org_apache_harmony_text_BidiWrapper_UBiDiDirection_UBIDI_MIXED 2L
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_open
+ * Signature: ()J
+ */
+  JNIEXPORT jlong JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1open
+    (JNIEnv *, jclass);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_close
+ * Signature: (J)V
+ */
+  JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1close
+    (JNIEnv *, jclass, jlong);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_setPara
+ * Signature: (J[CIB[B)V
+ */
+  JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setPara
+    (JNIEnv *, jclass, jlong, jcharArray, jint, jbyte, jbyteArray);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_setLine
+ * Signature: (JII)J
+ */
+  JNIEXPORT jlong JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setLine
+    (JNIEnv *, jclass, jlong, jint, jint);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_getDirection
+ * Signature: (J)I
+ */
+  JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getDirection
+    (JNIEnv *, jclass, jlong);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_getLength
+ * Signature: (J)I
+ */
+  JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLength
+    (JNIEnv *, jclass, jlong);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_getParaLevel
+ * Signature: (J)B
+ */
+  JNIEXPORT jbyte JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getParaLevel
+    (JNIEnv *, jclass, jlong);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_getLevels
+ * Signature: (J)[B
+ */
+  JNIEXPORT jbyteArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getLevels
+    (JNIEnv *, jclass, jlong);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_countRuns
+ * Signature: (J)I
+ */
+  JNIEXPORT jint JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1countRuns
+    (JNIEnv *, jclass, jlong);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_getRuns
+ * Signature: (J)[Lorg/apache/harmony/text/BidiRun;
+ */
+JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1getRuns
+  (JNIEnv *, jclass, jlong);
+/*
+ * Class:     org_apache_harmony_text_BidiWrapper
+ * Method:    ubidi_reorderVisual
+ * Signature: ([BI)[I
+ */
+  JNIEXPORT jintArray JNICALL
+    Java_org_apache_harmony_text_BidiWrapper_ubidi_1reorderVisual (JNIEnv *, jclass,
+                                                        jbyteArray, jint);
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/libcore/icu/src/main/native/BreakIteratorInterface.c b/libcore/icu/src/main/native/BreakIteratorInterface.c
new file mode 100644
index 0000000..021ace1
--- /dev/null
+++ b/libcore/icu/src/main/native/BreakIteratorInterface.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2006 The Android Open Source Project 
+ *
+ * Internal native functions.  All of the functions defined here make
+ * direct use of VM functions or data structures, so they can't be written
+ * with JNI and shouldn't really be in a shared library.
+ *
+ * All functions here either complete quickly or are used to enter a wait
+ * state, so we don't set the thread status to THREAD_NATIVE when executing
+ * these methods.  This means that the GC will wait for these functions
+ * to finish.  DO NOT perform long operations or blocking I/O in here.
+ *
+ * In some cases we're following the division of labor defined by GNU
+ * ClassPath, e.g. java.lang.Thread has "Thread" and "VMThread", with
+ * the VM-specific behavior isolated in VMThread.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "ErrorCode.h"
+#include "unicode/ubrk.h"
+#include "unicode/putil.h"
+#include <stdlib.h>
+
+static jstring getAvailableLocalesImpl(JNIEnv *env, jclass clazz, jint index) {
+
+    const char * locale = ubrk_getAvailable(index);
+
+    return (*env)->NewStringUTF(env, locale);
+
+}
+
+static jint getAvailableLocalesCountImpl(JNIEnv *env, jclass clazz) {
+    return ubrk_countAvailable();
+}
+
+static jint getCharacterInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
+
+    UBreakIterator *iter = ubrk_open(UBRK_CHARACTER, localeChars, NULL, 0, &status);
+
+    (*env)->ReleaseStringUTFChars(env, locale, localeChars);
+    
+    if ( icu4jni_error(env, status) != FALSE) {
+        return 0;
+    }
+
+    return (long) iter;
+}
+
+static jint getLineInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
+ 
+    UErrorCode status = U_ZERO_ERROR;
+
+    const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
+
+    enum UBreakIteratorType type = UBRK_LINE;
+
+    UBreakIterator *iter = ubrk_open(type, localeChars, NULL, 0, &status);
+
+    (*env)->ReleaseStringUTFChars(env, locale, localeChars);
+    
+    if ( icu4jni_error(env, status) != FALSE) {
+        return 0;
+    }
+
+    return (long) iter;
+}
+
+static jint getSentenceInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
+
+    enum UBreakIteratorType type = UBRK_SENTENCE;
+
+    UBreakIterator *iter = ubrk_open(type, localeChars, NULL, 0, &status);
+
+    (*env)->ReleaseStringUTFChars(env, locale, localeChars);
+    
+    if ( icu4jni_error(env, status) != FALSE) {
+        return 0;
+    }
+
+    return (long) iter;
+}
+
+static jint getWordInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
+
+    enum UBreakIteratorType type = UBRK_WORD;
+
+    UBreakIterator *iter = ubrk_open(type, localeChars, NULL, 0, &status);
+
+    (*env)->ReleaseStringUTFChars(env, locale, localeChars);
+    
+    if ( icu4jni_error(env, status) != FALSE) {
+        return 0;
+    }
+
+    return (long) iter;
+}
+
+static void closeBreakIteratorImpl(JNIEnv *env, jclass clazz, jint address) {
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    ubrk_close(bi);
+}
+
+static jint cloneImpl(JNIEnv *env, jclass clazz, jint address) {
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    jint buffersize = U_BRK_SAFECLONE_BUFFERSIZE;
+
+    UBreakIterator *iter = ubrk_safeClone(bi, NULL, &buffersize, &status);
+
+    if (icu4jni_error(env, status) != FALSE) {
+        return 0;
+    }
+
+    return (long) iter;
+}
+
+static void setTextImpl(JNIEnv *env, jclass clazz, jint address, jstring text) {
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    const UChar *strUChars = (*env)->GetStringChars(env, text, NULL);
+    int strLen = (*env)->GetStringLength(env, text);
+
+    ubrk_setText(bi, strUChars, strLen, &status);
+
+    (*env)->ReleaseStringChars(env, text, strUChars);
+
+    icu4jni_error(env, status);
+}
+
+static jboolean isBoundaryImpl(JNIEnv *env, jclass clazz, jint address, jint offset) {
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    return ubrk_isBoundary(bi, offset);
+}
+
+static jint nextImpl(JNIEnv *env, jclass clazz, jint address, jint n) {
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    if(n < 0) {
+        while(n++ < -1) {
+            ubrk_previous(bi);
+        }
+        return ubrk_previous(bi);
+    } else if(n == 0) {
+        return ubrk_current(bi);
+    } else {
+        while(n-- > 1) {
+            ubrk_next(bi);
+        }
+        return ubrk_next(bi);
+    }
+
+    return -1;
+}
+
+static jint precedingImpl(JNIEnv *env, jclass clazz, jint address, jint offset) {
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    return ubrk_preceding(bi, offset);
+}
+
+static jint firstImpl(JNIEnv *env, jclass clazz, jint address) {
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    return ubrk_first(bi);
+}
+
+static jint followingImpl(JNIEnv *env, jclass clazz, jint address, jint offset) {
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    return ubrk_following(bi, offset);
+}
+
+static jint currentImpl(JNIEnv *env, jclass clazz, jint address) {
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    return ubrk_current(bi);
+}
+
+static jint previousImpl(JNIEnv *env, jclass clazz, jint address) {
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    return ubrk_previous(bi);
+}
+
+static jint lastImpl(JNIEnv *env, jclass clazz, jint address) {
+
+    UBreakIterator *bi = (UBreakIterator *)(long)address;
+
+    return ubrk_last(bi);
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "getAvailableLocalesImpl", "(I)Ljava/lang/String;", 
+            (void*) getAvailableLocalesImpl },
+    { "getAvailableLocalesCountImpl", "()I", 
+            (void*) getAvailableLocalesCountImpl },
+    { "getCharacterInstanceImpl", "(Ljava/lang/String;)I", 
+            (void*) getCharacterInstanceImpl },
+    { "getLineInstanceImpl", "(Ljava/lang/String;)I", 
+            (void*) getLineInstanceImpl },
+    { "getSentenceInstanceImpl", "(Ljava/lang/String;)I", 
+            (void*) getSentenceInstanceImpl },
+    { "getWordInstanceImpl", "(Ljava/lang/String;)I", 
+            (void*) getWordInstanceImpl },
+    { "closeBreakIteratorImpl", "(I)V", 
+            (void*) closeBreakIteratorImpl },
+    { "cloneImpl", "(I)I", 
+            (void*) cloneImpl },
+    { "setTextImpl", "(ILjava/lang/String;)V", 
+            (void*) setTextImpl },
+    { "isBoundaryImpl", "(II)Z", 
+            (void*) isBoundaryImpl },
+    { "nextImpl", "(II)I", 
+            (void*) nextImpl },
+    { "precedingImpl", "(II)I", 
+            (void*) precedingImpl },
+    { "firstImpl", "(I)I", 
+            (void*) firstImpl },
+    { "lastImpl", "(I)I", 
+            (void*) lastImpl },
+    { "currentImpl", "(I)I", 
+            (void*) currentImpl },
+    { "followingImpl", "(II)I", 
+            (void*) followingImpl },
+    { "previousImpl", "(I)I", 
+            (void*) previousImpl },
+};
+int register_com_ibm_icu4jni_text_NativeBreakIterator(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "com/ibm/icu4jni/text/NativeBreakIterator",
+                gMethods, NELEM(gMethods));
+}
diff --git a/libcore/icu/src/main/native/CharacterInterface.c b/libcore/icu/src/main/native/CharacterInterface.c
new file mode 100644
index 0000000..70e9f29
--- /dev/null
+++ b/libcore/icu/src/main/native/CharacterInterface.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2006 The Android Open Source Project 
+ *
+ * Internal native functions.  All of the functions defined here make
+ * direct use of VM functions or data structures, so they can't be written
+ * with JNI and shouldn't really be in a shared library.
+ *
+ * All functions here either complete quickly or are used to enter a wait
+ * state, so we don't set the thread status to THREAD_NATIVE when executing
+ * these methods.  This means that the GC will wait for these functions
+ * to finish.  DO NOT perform long operations or blocking I/O in here.
+ *
+ * In some cases we're following the division of labor defined by GNU
+ * ClassPath, e.g. java.lang.Thread has "Thread" and "VMThread", with
+ * the VM-specific behavior isolated in VMThread.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/uchar.h"
+#include <stdlib.h>
+#include <math.h>
+
+static jint digitImpl(JNIEnv *env, jclass clazz, jint codePoint, jint radix) {
+    return u_digit(codePoint, radix);
+}
+
+static jint getTypeImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_charType(codePoint);
+}
+
+static jbyte getDirectionalityImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_charDirection (codePoint);
+}
+
+static jboolean isMirroredImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_isMirrored (codePoint);
+}
+
+static jint getNumericValueImpl(JNIEnv *env, jclass clazz, jint codePoint){
+    // The letters A-Z in their uppercase ('\u0041' through '\u005A'), 
+    //                          lowercase ('\u0061' through '\u007A'), 
+    //             and full width variant ('\uFF21' through '\uFF3A' 
+    //                                 and '\uFF41' through '\uFF5A') forms 
+    // have numeric values from 10 through 35. This is independent of the 
+    // Unicode specification, which does not assign numeric values to these 
+    // char values.
+    if (codePoint >= 0x41 && codePoint <= 0x5A) {
+        return codePoint - 0x37;
+    }
+    if (codePoint >= 0x61 && codePoint <= 0x7A) {
+        return codePoint - 0x57;
+    }
+    if (codePoint >= 0xFF21 && codePoint <= 0xFF3A) {
+        return codePoint - 0xFF17;
+    }
+    if (codePoint >= 0xFF41 && codePoint <= 0xFF5A) {
+        return codePoint - 0xFF37;
+    }
+
+    double result = u_getNumericValue(codePoint);
+
+    if (result == U_NO_NUMERIC_VALUE) {
+        return -1;
+    } else if (result < 0 || floor(result + 0.5) != result) {
+        return -2;
+    }
+
+    return result;
+} 
+    
+static jboolean isDefinedValueImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_isdefined(codePoint);
+} 
+
+static jboolean isDigitImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_isdigit(codePoint);
+} 
+
+static jboolean isIdentifierIgnorableImpl(JNIEnv *env, jclass clazz, 
+        jint codePoint) {
+
+    // Java also returns TRUE for U+0085 Next Line (it omits U+0085 from whitespace ISO controls)
+    if(codePoint == 0x0085) {
+        return JNI_TRUE;
+    }
+
+    return u_isIDIgnorable(codePoint);
+} 
+
+static jboolean isLetterImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_isalpha(codePoint);
+} 
+
+static jboolean isLetterOrDigitImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_isalnum(codePoint);
+} 
+
+static jboolean isSpaceCharImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_isJavaSpaceChar(codePoint);
+} 
+
+static jboolean isTitleCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_istitle(codePoint);
+} 
+
+static jboolean isUnicodeIdentifierPartImpl(JNIEnv *env, jclass clazz, 
+        jint codePoint) {
+    return u_isIDPart(codePoint);
+} 
+
+static jboolean isUnicodeIdentifierStartImpl(JNIEnv *env, jclass clazz, 
+        jint codePoint) {
+    return u_isIDStart(codePoint);
+} 
+
+static jboolean isWhitespaceImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+
+    // Java omits U+0085
+    if(codePoint == 0x0085) {
+        return JNI_FALSE;
+    }
+
+    return u_isWhitespace(codePoint);
+} 
+
+static jint toLowerCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_tolower(codePoint);
+} 
+
+static jint toTitleCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_totitle(codePoint);
+} 
+
+static jint toUpperCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_toupper(codePoint);
+} 
+
+static jboolean isUpperCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_isupper(codePoint);
+} 
+
+static jboolean isLowerCaseImpl(JNIEnv *env, jclass clazz, jint codePoint) {
+    return u_islower(codePoint);
+} 
+
+static int forName(JNIEnv *env, jclass clazz, jstring blockName) {
+    const char *bName = (*env)->GetStringUTFChars(env, blockName, NULL);
+    int result =  u_getPropertyValueEnum(UCHAR_BLOCK, bName);
+    (*env)->ReleaseStringUTFChars(env, blockName, bName);
+    return result;
+}
+
+static int codeBlock(JNIEnv *env, jclass clazz, jint codePoint) {
+    return ublock_getCode(codePoint);
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "digitImpl", "(II)I", (void*) digitImpl },
+    { "getTypeImpl", "(I)I", (void*) getTypeImpl },
+    { "getDirectionalityImpl", "(I)B", (void*) getDirectionalityImpl },
+    { "isMirroredImpl", "(I)Z", (void*) isMirroredImpl },
+    { "getNumericValueImpl", "(I)I", (void*) getNumericValueImpl },
+    { "isDefinedValueImpl", "(I)Z", (void*) isDefinedValueImpl },
+    { "isDigitImpl", "(I)Z", (void*) isDigitImpl },
+    { "isIdentifierIgnorableImpl", "(I)Z", (void*) isIdentifierIgnorableImpl },
+    { "isLetterImpl", "(I)Z", (void*) isLetterImpl },
+    { "isLetterOrDigitImpl", "(I)Z", (void*) isLetterOrDigitImpl },
+    { "isSpaceCharImpl", "(I)Z", (void*) isSpaceCharImpl },
+    { "isTitleCaseImpl", "(I)Z", (void*) isTitleCaseImpl },
+    { "isUnicodeIdentifierPartImpl", "(I)Z",
+            (void*) isUnicodeIdentifierPartImpl },
+    { "isUnicodeIdentifierStartImpl", "(I)Z",
+            (void*) isUnicodeIdentifierStartImpl },
+    { "isWhitespaceImpl", "(I)Z", (void*) isWhitespaceImpl },
+    { "toLowerCaseImpl", "(I)I", (void*) toLowerCaseImpl },
+    { "toTitleCaseImpl", "(I)I", (void*) toTitleCaseImpl },
+    { "toUpperCaseImpl", "(I)I", (void*) toUpperCaseImpl },
+    { "isUpperCaseImpl", "(I)Z", (void*) isUpperCaseImpl },
+    { "isLowerCaseImpl", "(I)Z", (void*) isLowerCaseImpl },
+    { "forname", "(Ljava/lang/String;)I", (void*) forName },
+    { "codeblock", "(I)I", (void*) codeBlock }
+}; 
+
+int register_com_ibm_icu4jni_lang_UCharacter(JNIEnv *env) {
+    return jniRegisterNativeMethods(env, "com/ibm/icu4jni/lang/UCharacter",
+                gMethods, NELEM(gMethods));
+}
+
+
diff --git a/libcore/icu/src/main/native/CollationInterface.c b/libcore/icu/src/main/native/CollationInterface.c
new file mode 100644
index 0000000..86246ac
--- /dev/null
+++ b/libcore/icu/src/main/native/CollationInterface.c
@@ -0,0 +1,589 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "ErrorCode.h"
+#include "unicode/ucol.h"
+#include "unicode/ucoleitr.h"
+#include "ucol_imp.h"
+
+
+/**
+* Closing a C UCollator with the argument locale rules.
+* Note determining if a collator currently exist for the caller is to be handled
+* by the caller. Hence if the caller has a existing collator, it is his 
+* responsibility to delete first before calling this method.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C UCollator
+*/
+static void closeCollator(JNIEnv *env, jclass obj,
+        jint address) { 
+
+  UCollator *collator = (UCollator *)(int)address;
+  ucol_close(collator);
+}
+
+
+/**
+* Close a C collation element iterator.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of C collation element iterator to close.
+*/
+static void closeElements(JNIEnv *env, jclass obj,
+        jint address) {
+
+  UCollationElements *iterator = (UCollationElements *)(int)address;
+  ucol_closeElements(iterator);
+}
+
+/**
+* Compare two strings.
+* The strings will be compared using the normalization mode and options
+* specified in openCollator or openCollatorFromRules
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of the c collator
+* @param source The source string.
+* @param target The target string.
+* @return result of the comparison, UCOL_EQUAL, UCOL_GREATER or UCOL_LESS
+*/
+static jint compare(JNIEnv *env, jclass obj, jint address,
+        jstring source, jstring target) {
+
+    const UCollator *collator  = (const UCollator *)(int)address;
+    jint result = -2;
+    if(collator){
+        jsize       srclength = (*env)->GetStringLength(env, source);
+        const UChar *srcstr   = (const UChar *)(*env)->GetStringCritical(env,source,0);
+        if(srcstr){
+            jsize       tgtlength = (*env)->GetStringLength(env, target);
+            const UChar *tgtstr    = (const UChar *)(*env)->GetStringCritical(env,target,0);
+            if(tgtstr){ 
+                  result = ucol_strcoll(collator, srcstr, srclength, tgtstr, tgtlength);
+                  (*env)->ReleaseStringCritical(env, source, srcstr);
+                  (*env)->ReleaseStringCritical(env, target, tgtstr);
+                  return result;
+            }else{
+                icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+            }
+        }else{
+            icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+        }
+    }else{
+        icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+    }
+    return result;
+}
+
+/**
+* Universal attribute getter
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of the C collator
+* @param type type of attribute to be set
+* @return attribute value
+* @exception thrown when error occurs while getting attribute value
+*/
+static jint getAttribute(JNIEnv *env, jclass obj, jint address,
+        jint type) {
+
+    const UCollator *collator = (const UCollator *)(int)address;
+    UErrorCode status = U_ZERO_ERROR;
+    if(collator){
+        jint result = (jint)ucol_getAttribute(collator, (UColAttribute)type, 
+                                            &status);
+        if (icu4jni_error(env, status) != FALSE){
+            return (jint)UCOL_DEFAULT;
+        }
+        return result;
+    }else{
+        icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+    }
+    return (jint)UCOL_DEFAULT;
+}
+
+/** 
+* Create a CollationElementIterator object that will iterator over the elements 
+* in a string, using the collation rules defined in this RuleBasedCollatorJNI
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of C collator
+* @param source string to iterate over
+* @return address of C collationelement
+*/
+static jint getCollationElementIterator(JNIEnv *env,
+        jclass obj, jint address, jstring source) {
+
+    UErrorCode status    = U_ZERO_ERROR;
+    UCollator *collator  = (UCollator *)(int)address;
+    jint       result=0;
+    if(collator){
+        jsize srclength     = (*env)->GetStringLength(env, source);
+        const UChar *srcstr = (const UChar *)(*env)->GetStringCritical(env,source,0);
+        if(srcstr){
+            result = (jint)(ucol_openElements(collator, srcstr, srclength, &status));
+
+            (*env)->ReleaseStringCritical(env, source, srcstr);
+            icu4jni_error(env, status);
+        }else{
+            icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR);
+        }
+    }else{
+        icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR);
+    }
+    return result;
+}
+
+/**
+* Get the maximum length of any expansion sequences that end with the specified 
+* comparison order.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C collation element iterator containing the text.
+* @param order collation order returned by previous or next.
+* @return maximum length of any expansion sequences ending with the specified 
+*         order or 1 if collation order does not occur at the end of any 
+*         expansion sequence.
+*/
+static jint getMaxExpansion(JNIEnv *env, jclass obj,
+        jint address, jint order) {
+
+  UCollationElements *iterator = (UCollationElements *)(int)address;
+  return ucol_getMaxExpansion(iterator, order);
+}
+
+/**
+* Get the normalization mode for this object.
+* The normalization mode influences how strings are compared.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of C collator
+* @return normalization mode; one of the values from NormalizerEnum
+*/
+static jint getNormalization(JNIEnv *env, jclass obj,
+        jint address) {
+
+  UErrorCode status = U_ZERO_ERROR;
+  const UCollator *collator = (const UCollator *)(int)address;
+  if(U_FAILURE(status)){
+       icu4jni_error(env, status);
+  }
+  return (jint)ucol_getAttribute(collator,UCOL_NORMALIZATION_MODE,&status);
+
+}
+
+/**
+* Set the normalization mode for this object.
+* The normalization mode influences how strings are compared.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of C collator
+* @param mode the normalization mode
+*/
+static void setNormalization(JNIEnv *env, jclass obj, jint address, 
+        jint mode) {
+
+    UErrorCode status = U_ZERO_ERROR;
+    const UCollator *collator = (const UCollator *)(int)address;
+    if(U_FAILURE(status)){
+        icu4jni_error(env, status);
+    }
+    ucol_setAttribute(collator,UCOL_NORMALIZATION_MODE,mode,&status);
+}
+
+
+/**
+* Get the offset of the current source character.
+* This is an offset into the text of the character containing the current
+* collation elements.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param addresss of the C collation elements iterator to query.
+* @return offset of the current source character.
+*/
+static jint getOffset(JNIEnv *env, jclass obj, jint address) {
+
+  UCollationElements *iterator = (UCollationElements *)(int)address;
+  return ucol_getOffset(iterator);
+}
+
+/**
+* Get the collation rules from a UCollator.
+* The rules will follow the rule syntax.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address the address of the C collator
+* @return collation rules.
+*/
+static jstring getRules(JNIEnv *env, jclass obj,
+        jint address) {
+
+  const UCollator *collator = (const UCollator *)(int)address;
+  int32_t length=0;
+  const UChar *rules = ucol_getRules(collator, &length);
+  return (*env)->NewString(env, rules, length);
+}
+
+/**
+* Get a sort key for the argument string
+* Sort keys may be compared using java.util.Arrays.equals
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of the C collator
+* @param source string for key to be generated
+* @return sort key
+*/
+static jbyteArray getSortKey(JNIEnv *env, jclass obj,
+        jint address, jstring source) {
+
+  const UCollator *collator  = (const UCollator *)(int)address;
+  jbyteArray result;
+  if(collator && source){
+      // BEGIN android-added
+      if(!source) {
+          return NULL;
+      }
+      // END android-added
+      jsize srclength            = (*env)->GetStringLength(env, source);
+      const UChar *srcstr        = (const UChar *)(*env)->GetStringCritical(env,source, 0);
+      if(srcstr){
+// BEGIN android-changed
+          uint8_t bytearray[UCOL_MAX_BUFFER * 2];
+          uint8_t *largerbytearray = NULL;
+          uint8_t *usedbytearray = bytearray;
+  
+          jint bytearraysize = ucol_getSortKey(collator, srcstr, srclength, bytearray, 
+                                               sizeof(bytearray) - 1);
+ 
+          if (bytearraysize > sizeof(bytearray) - 1) {
+            // didn't fit, try again with a larger buffer.
+            largerbytearray = malloc(bytearraysize + 1);
+            usedbytearray = largerbytearray;
+            bytearraysize = ucol_getSortKey(collator, srcstr, srclength, largerbytearray, 
+                                               bytearraysize);
+          }
+ 
+          (*env)->ReleaseStringCritical(env, source, srcstr);
+
+          if (bytearraysize == 0) {
+            free(largerbytearray);
+            return NULL;
+          }
+  
+          /* no problem converting uint8_t to int8_t, gives back the correct value
+           * tried and tested
+           */
+          result = (*env)->NewByteArray(env, bytearraysize);
+          (*env)->SetByteArrayRegion(env, result, 0, bytearraysize, usedbytearray);
+          free(largerbytearray);
+// END android-changed
+      }else{
+          icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+      }
+  }else{
+    icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+  }
+  return result;
+}
+
+/**
+* Returns a hash of this collation object
+* Note this method is not complete, it only returns 0 at the moment.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of C collator
+* @return hash of this collation object
+*/
+static jint hashCode(JNIEnv *env, jclass obj, jint address) {
+	
+  UCollator *collator = (UCollator *)(int)address;
+  int32_t length=0;
+  const UChar *rules = ucol_getRules(collator, &length);
+  /* temporary commented out
+   * return uhash_hashUCharsN(rules, length);
+   */
+  return 0;
+}
+
+/**
+* Get the ordering priority of the next collation element in the text.
+* A single character may contain more than one collation element.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address if C collation elements containing the text.
+* @return next collation elements ordering, otherwise returns NULLORDER if an 
+*         error has occured or if the end of string has been reached
+*/
+static jint next(JNIEnv *env, jclass obj, jint address) {
+  UCollationElements *iterator = (UCollationElements *)(int)address;
+  UErrorCode status = U_ZERO_ERROR;
+  jint result = ucol_next(iterator, &status);
+
+   icu4jni_error(env, status);
+  return result;
+}
+
+/**
+* Opening a new C UCollator with the default locale.
+* Note determining if a collator currently exist for the caller is to be handled
+* by the caller. Hence if the caller has a existing collator, it is his 
+* responsibility to delete first before calling this method.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @return address of the new C UCollator
+* @exception thrown if creation of the UCollator fails
+*/
+static jint openCollator__(JNIEnv *env, jclass obj) {
+  jint result;
+  UErrorCode status = U_ZERO_ERROR;
+
+  result = (jint)ucol_open(NULL, &status);
+  if ( icu4jni_error(env, status) != FALSE)
+    return 0;
+ 
+  return result;
+}
+
+
+/**
+* Opening a new C UCollator with the argument locale rules.
+* Note determining if a collator currently exist for the caller is to be handled
+* by the caller. Hence if the caller has a existing collator, it is his 
+* responsibility to delete first before calling this method.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param locale name
+* @return address of the new C UCollator
+* @exception thrown if creation of the UCollator fails
+*/
+static jint openCollator__Ljava_lang_String_2(JNIEnv *env,
+        jclass obj, jstring locale) {
+
+  /* this will be null terminated */
+  const char *localestr = (*env)->GetStringUTFChars(env, locale, 0);
+  jint result=0;
+  UErrorCode status = U_ZERO_ERROR;
+
+  if(localestr){
+      result = (jint)ucol_open(localestr, &status);
+      (*env)->ReleaseStringUTFChars(env, locale, localestr);
+      icu4jni_error(env, status);
+  }else{
+      icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+  }
+  return result;
+}
+
+/**
+* Opening a new C UCollator with the argument locale rules.
+* Note determining if a collator currently exist for the caller is to be 
+* handled by the caller. Hence if the caller has a existing collator, it is his 
+* responsibility to delete first before calling this method.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param rules set of collation rules
+* @param normalizationmode normalization mode
+* @param strength collation strength
+* @return address of the new C UCollator
+* @exception thrown if creation of the UCollator fails
+*/
+static jint openCollatorFromRules(JNIEnv *env, jclass obj,
+        jstring rules, jint normalizationmode, jint strength) {
+
+  jsize  ruleslength    = (*env)->GetStringLength(env, rules);
+  const UChar *rulestr  = (const UChar *)(*env)->GetStringCritical(env,rules, 0);
+  UErrorCode status     = U_ZERO_ERROR;
+  jint   result        = 0;
+  if(rulestr){
+      result = (jint)ucol_openRules(rulestr, ruleslength, 
+                                   (UColAttributeValue)normalizationmode,
+                                   (UCollationStrength)strength, NULL, &status);
+
+      (*env)->ReleaseStringCritical(env, rules, rulestr);
+      icu4jni_error(env, status);
+  }else{
+      icu4jni_error(env,U_ILLEGAL_ARGUMENT_ERROR);
+  }
+
+  return result;
+}
+
+/**
+* Get the ordering priority of the previous collation element in the text.
+* A single character may contain more than one collation element.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C collation element iterator containing the text.
+* @return previous collation element ordering, otherwise returns NULLORDER if 
+*         an error has occured or if the start of string has been reached
+* @exception thrown when retrieval of previous collation element fails.
+*/
+static jint previous(JNIEnv *env, jclass obj, jint address) {
+
+  UCollationElements *iterator = (UCollationElements *)(int)address;
+  UErrorCode status = U_ZERO_ERROR;
+  jint result = ucol_previous(iterator, &status);
+
+   icu4jni_error(env, status);
+  return result;
+}
+
+
+/**
+* Reset the collation elements to their initial state.
+* This will move the 'cursor' to the beginning of the text.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of C collation element iterator to reset.
+*/
+static void reset(JNIEnv *env, jclass obj, jint address) {
+
+  UCollationElements *iterator = (UCollationElements *)(int)address;
+  ucol_reset(iterator);
+}
+
+/**
+* Thread safe cloning operation
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of C collator to be cloned
+* @return address of the new clone
+* @exception thrown when error occurs while cloning
+*/
+static jint safeClone(JNIEnv *env, jclass obj, jint address) {
+
+  const UCollator *collator = (const UCollator *)(int)address;
+  UErrorCode status = U_ZERO_ERROR;
+  jint result;
+  jint buffersize = U_COL_SAFECLONE_BUFFERSIZE;
+
+  result = (jint)ucol_safeClone(collator, NULL, &buffersize, &status);
+
+  if ( icu4jni_error(env, status) != FALSE) {
+    return 0;
+  }
+ 
+  return result;
+}
+
+/**
+* Universal attribute setter.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address address of the C collator
+* @param type type of attribute to be set
+* @param value attribute value
+* @exception thrown when error occurs while setting attribute value
+*/
+static void setAttribute(JNIEnv *env, jclass obj, jint address,
+        jint type, jint value) {
+
+  UCollator *collator = (UCollator *)(int)address;
+  UErrorCode status = U_ZERO_ERROR;
+  ucol_setAttribute(collator, (UColAttribute)type, (UColAttributeValue)value, 
+                    &status);
+   icu4jni_error(env, status);
+}
+
+/**
+* Set the offset of the current source character.
+* This is an offset into the text of the character to be processed.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C collation element iterator to set.
+* @param offset The desired character offset.
+* @exception thrown when offset setting fails
+*/
+static void setOffset(JNIEnv *env, jclass obj, jint address,
+        jint offset) {
+
+  UCollationElements *iterator = (UCollationElements *)(int)address;
+  UErrorCode status = U_ZERO_ERROR;
+
+  ucol_setOffset(iterator, offset, &status);
+   icu4jni_error(env, status);
+}
+
+/**
+* Set the text containing the collation elements.
+* @param env JNI environment
+* @param obj RuleBasedCollatorJNI object
+* @param address of the C collation element iterator to be set
+* @param source text containing the collation elements.
+* @exception thrown when error occurs while setting offset
+*/
+static void setText(JNIEnv *env, jclass obj, jint address,
+        jstring source) {
+
+  UCollationElements *iterator = (UCollationElements *)(int)address;
+  UErrorCode status = U_ZERO_ERROR;
+  int strlength = (*env)->GetStringLength(env, source);
+  const UChar *str = (const UChar *)(*env)->GetStringCritical(env, source, 0);
+  
+  ucol_setText(iterator, str, strlength, &status);
+  (*env)->ReleaseStringCritical(env, source, str);
+
+   icu4jni_error(env, status);
+}
+
+// BEGIN android-added
+static jstring getAvailableLocalesImpl(JNIEnv *env, jclass clazz, jint index) {
+
+    const char * locale = ucol_getAvailable(index);
+
+    return (*env)->NewStringUTF(env, locale);
+
+}
+
+static jint getAvailableLocalesCountImpl(JNIEnv *env, jclass clazz) {
+    return ucol_countAvailable();
+}
+// END android-added
+
+/*
+ * JNI registratio
+ */
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    // BEGIN android-added
+    { "getAvailableLocalesImpl", "(I)Ljava/lang/String;", (void*) getAvailableLocalesImpl },
+    { "getAvailableLocalesCountImpl", "()I", (void*) getAvailableLocalesCountImpl },
+    // END android-added
+    { "openCollator", "()I", (void*) openCollator__ },
+    { "openCollator", "(Ljava/lang/String;)I", (void*) openCollator__Ljava_lang_String_2 },
+    { "openCollatorFromRules", "(Ljava/lang/String;II)I", (void*) openCollatorFromRules },
+    { "closeCollator", "(I)V", (void*) closeCollator },
+    { "compare", "(ILjava/lang/String;Ljava/lang/String;)I", (void*) compare },
+    { "getNormalization", "(I)I", (void*) getNormalization },
+    { "setNormalization", "(II)V", (void*) setNormalization },
+    { "getRules", "(I)Ljava/lang/String;", (void*) getRules },
+    { "getSortKey", "(ILjava/lang/String;)[B", (void*) getSortKey },
+    { "setAttribute", "(III)V", (void*) setAttribute },
+    { "getAttribute", "(II)I", (void*) getAttribute },
+    { "safeClone", "(I)I", (void*) safeClone },
+    { "getCollationElementIterator", "(ILjava/lang/String;)I", (void*) getCollationElementIterator },
+    { "hashCode", "(I)I", (void*) hashCode },
+    { "closeElements", "(I)V", (void*) closeElements },
+    { "reset", "(I)V", (void*) reset },
+    { "next", "(I)I", (void*) next },
+    { "previous", "(I)I", (void*) previous },
+    { "getMaxExpansion", "(II)I", (void*) getMaxExpansion },
+    { "setText", "(ILjava/lang/String;)V", (void*) setText },
+    { "getOffset", "(I)I", (void*) getOffset },
+    { "setOffset", "(II)V", (void*) setOffset }
+};
+
+int register_com_ibm_icu4jni_text_NativeCollator(JNIEnv *_env) { 
+    return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/text/NativeCollation",
+                gMethods, NELEM(gMethods));
+}
+
diff --git a/libcore/icu/src/main/native/CollationInterface.h b/libcore/icu/src/main/native/CollationInterface.h
new file mode 100644
index 0000000..bdb4b67
--- /dev/null
+++ b/libcore/icu/src/main/native/CollationInterface.h
@@ -0,0 +1,214 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class CollationInterface */
+
+#ifndef _Included_com_ibm_icu4jni_text_NativeCollation
+#define _Included_com_ibm_icu4jni_text_NativeCollation
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    closeCollator
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_closeCollator
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    closeElements
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_closeElements
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    compare
+ * Signature: (JLjava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_compare
+  (JNIEnv *, jclass, jlong, jstring, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    getAttribute
+ * Signature: (JI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getAttribute
+  (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    getCollationElementIterator
+ * Signature: (JLjava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getCollationElementIterator
+  (JNIEnv *, jclass, jlong, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    getMaxExpansion
+ * Signature: (JI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getMaxExpansion
+  (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    getNormalization
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getNormalization
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    getOffset
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getOffset
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    getRules
+ * Signature: (J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getRules
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    getSortKey
+ * Signature: (JLjava/lang/String;)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_com_ibm_icu4jni_text_NativeCollation_getSortKey
+  (JNIEnv *, jclass, jlong, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    hashCode
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_hashCode
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    next
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_next
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    openCollator
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_openCollator__
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    openCollator
+ * Signature: (Ljava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_openCollator__Ljava_lang_String_2
+  (JNIEnv *, jclass, jstring);
+
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    openCollatorFromRules
+ * Signature: (Ljava/lang/String;II)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_openCollatorFromRules
+  (JNIEnv *, jclass, jstring, jint, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    previous
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_previous
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    primaryOrder
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_primaryOrder
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    reset
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_reset
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    safeClone
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ibm_icu4jni_text_NativeCollation_safeClone
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    secondaryOrder
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_secondaryOrder
+  (JNIEnv *, jclass, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    setAttribute
+ * Signature: (JII)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_setAttribute
+  (JNIEnv *, jclass, jlong, jint, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    setOffset
+ * Signature: (JI)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_setOffset
+  (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    setText
+ * Signature: (JLjava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_text_NativeCollation_setText
+  (JNIEnv *, jclass, jlong, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_text_NativeCollation
+ * Method:    tertiaryOrder
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_text_NativeCollation_tertiaryOrder
+  (JNIEnv *, jclass, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/libcore/icu/src/main/native/ConverterInterface.c b/libcore/icu/src/main/native/ConverterInterface.c
new file mode 100644
index 0000000..1a16197
--- /dev/null
+++ b/libcore/icu/src/main/native/ConverterInterface.c
@@ -0,0 +1,1365 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2006, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*
+*******************************************************************************
+*/
+/*
+ *  @(#) icujniinterface.c	1.2 00/10/11
+ *
+ * (C) Copyright IBM Corp. 2000 - All Rights Reserved
+ *  A JNI wrapper to ICU native converter Interface
+ * @author: Ram Viswanadha
+ */
+
+#include "ConverterInterface.h"
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/utypes.h"   /* Basic ICU data types */
+#include "unicode/ucnv.h"     /* C   Converter API    */
+#include "unicode/ustring.h"  /* some more string functions*/
+#include "unicode/ucnv_cb.h"  /* for callback functions */
+#include "unicode/uset.h"     /* for contains function */
+#include "ErrorCode.h"
+#include <stdlib.h>
+#include <string.h>
+
+// BEGIN android-removed
+// #define UTF_16BE "UTF-16BE" 
+// #define UTF_16 "UTF-16" 
+// END android-removed
+	 	  
+/* Prototype of callback for substituting user settable sub chars */
+void  JNI_TO_U_CALLBACK_SUBSTITUTE
+ (const void *,UConverterToUnicodeArgs *,const char* ,int32_t ,UConverterCallbackReason ,UErrorCode * );
+
+/**
+ * Opens the ICU converter
+ * @param env environment handle for JNI 
+ * @param jClass handle for the class
+ * @param handle buffer to recieve ICU's converter address
+ * @param converterName name of the ICU converter
+ */
+static jlong openConverter (JNIEnv *env, jclass jClass, jstring converterName) {
+
+    UConverter* conv=NULL;
+    UErrorCode errorCode = U_ZERO_ERROR;
+
+    const char* cnvName= (const char*) (*env)->GetStringUTFChars(env, converterName,NULL);
+    if(cnvName) {
+        int count = (*env)->GetStringUTFLength(env,converterName);
+
+        conv = ucnv_open(cnvName,&errorCode);
+    }
+    (*env)->ReleaseStringUTFChars(env, converterName,cnvName);
+
+    if (icu4jni_error(env, errorCode) != FALSE) {
+        return 0;
+    }
+
+    return (jlong) conv;
+}
+
+/**
+ * Closes the ICU converter
+ * @param env environment handle for JNI 
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ */
+static void closeConverter (JNIEnv *env, jclass jClass, jlong handle) {
+     
+    UConverter* cnv = (UConverter*)(long)handle;
+    if(cnv) {
+        // BEGIN android-added
+        // Free up any contexts created in setCallback[Encode|Decode]()
+        UConverterToUCallback toAction;
+        UConverterFromUCallback fromAction;
+        void * context1 = NULL;
+        void * context2 = NULL;
+        ucnv_getToUCallBack(cnv, &toAction, &context1);
+        ucnv_getFromUCallBack(cnv, &fromAction, &context2);
+        // END android-added
+        ucnv_close(cnv);
+        // BEGIN android-added
+        if (context1 != NULL) {
+            free(context1);
+        }
+        if (context2 != NULL) {
+            free(context2);
+        }
+        // END android-added
+    }
+}
+
+/**
+ * Sets the substution mode for from Unicode conversion. Currently only 
+ * two modes are supported: substitute or report
+ * @param env environment handle for JNI 
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ * @param mode the mode to set 
+ */
+static jint setSubstitutionModeCharToByte (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) {
+    
+    UConverter* conv = (UConverter*)(long)handle;
+    UErrorCode errorCode =U_ZERO_ERROR;
+
+    if(conv) {
+        
+        UConverterFromUCallback fromUOldAction ;
+        void* fromUOldContext;
+        void* fromUNewContext=NULL;
+        if(mode) {
+
+            ucnv_setFromUCallBack(conv,
+               UCNV_FROM_U_CALLBACK_SUBSTITUTE,
+               fromUNewContext,
+               &fromUOldAction,
+               (const void**)&fromUOldContext,
+               &errorCode);
+
+        }
+        else{
+
+            ucnv_setFromUCallBack(conv,
+               UCNV_FROM_U_CALLBACK_STOP,
+               fromUNewContext,
+               &fromUOldAction,
+               (const void**)&fromUOldContext,
+               &errorCode);
+         
+        }
+        return errorCode;
+    }
+    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+    return errorCode;
+}
+/**
+ * Sets the substution mode for to Unicode conversion. Currently only 
+ * two modes are supported: substitute or report
+ * @param env environment handle for JNI 
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ * @param mode the mode to set 
+ */
+static jint setSubstitutionModeByteToChar (JNIEnv *env, jclass jClass, jlong handle, jboolean mode) {
+    
+    UConverter* conv = (UConverter*)handle;
+    UErrorCode errorCode =U_ZERO_ERROR;
+
+    if(conv) {
+        
+        UConverterToUCallback toUOldAction ;
+        void* toUOldContext;
+        void* toUNewContext=NULL;
+        if(mode) {
+
+            ucnv_setToUCallBack(conv,
+               UCNV_TO_U_CALLBACK_SUBSTITUTE,
+               toUNewContext,
+               &toUOldAction,
+               (const void**)&toUOldContext,
+               &errorCode);
+
+        }
+        else{
+
+            ucnv_setToUCallBack(conv,
+               UCNV_TO_U_CALLBACK_STOP,
+               toUNewContext,
+               &toUOldAction,
+               (const void**)&toUOldContext,
+               &errorCode);
+         
+        }
+        return errorCode;
+    }
+    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+    return errorCode;
+}
+/**
+ * Converts a buffer of Unicode code units to target encoding 
+ * @param env environment handle for JNI 
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ * @param source buffer of Unicode chars to convert 
+ * @param sourceEnd limit of the source buffer
+ * @param target buffer to recieve the converted bytes
+ * @param targetEnd the limit of the target buffer
+ * @param data buffer to recieve state of the current conversion
+ * @param flush boolean that specifies end of source input
+ */
+static jint convertCharToByte(JNIEnv *env, jclass jClass, jlong handle,  jcharArray source,  jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) {
+    
+
+    UErrorCode errorCode =U_ZERO_ERROR;
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+        jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+        if(myData) {
+            jint* sourceOffset = &myData[0];
+            jint* targetOffset = &myData[1];
+            const jchar* uSource =(jchar*) (*env)->GetPrimitiveArrayCritical(env,source, NULL);
+            if(uSource) {
+                jbyte* uTarget=(jbyte*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
+                if(uTarget) {
+                    const jchar* mySource = uSource+ *sourceOffset;
+                    const UChar* mySourceLimit= uSource+sourceEnd;
+                    char* cTarget=uTarget+ *targetOffset;
+                    const char* cTargetLimit=uTarget+targetEnd;
+                    
+                    ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource,
+                                    mySourceLimit,NULL,(UBool) flush, &errorCode);
+
+                    *sourceOffset = (jint) (mySource - uSource)-*sourceOffset;
+                    *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset;
+                    if(U_FAILURE(errorCode)) {
+                        (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+                        (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
+                        (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+                        return errorCode;
+                    }
+                }else{
+                    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+                }
+                (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+            }else{
+                    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+            }
+            (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0); 
+        }else{
+                    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+        return errorCode;
+    }
+    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+    return errorCode;
+}
+
+static jint encode(JNIEnv *env, jclass jClass, jlong handle, jcharArray source, jint sourceEnd, jbyteArray target, jint targetEnd, jintArray data, jboolean flush) {
+   
+    UErrorCode ec = convertCharToByte(env,jClass,handle,source,sourceEnd, target,targetEnd,data,flush);
+    UConverter* cnv = (UConverter*)handle;
+    jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+
+    if(cnv && myData) {
+        
+       UErrorCode errorCode = U_ZERO_ERROR;
+       myData[3] = ucnv_fromUCountPending(cnv, &errorCode);
+
+       if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND) {
+            int8_t count =32;
+            UChar invalidUChars[32];
+            ucnv_getInvalidUChars(cnv,invalidUChars,&count,&errorCode);
+
+            if(U_SUCCESS(errorCode)) {
+                myData[2] = count;
+            }	  
+        }
+    }
+    (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+    return ec;
+}
+
+/**
+ * Converts a buffer of encoded bytes to Unicode code units
+ * @param env environment handle for JNI 
+ * @param jClass handle for the class
+ * @param handle address of ICU converter
+ * @param source buffer of Unicode chars to convert 
+ * @param sourceEnd limit of the source buffer
+ * @param target buffer to recieve the converted bytes
+ * @param targetEnd the limit of the target buffer
+ * @param data buffer to recieve state of the current conversion
+ * @param flush boolean that specifies end of source input
+ */
+static jint convertByteToChar(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) {
+
+    UErrorCode errorCode =U_ZERO_ERROR;
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+        jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+        if(myData) {
+            jint* sourceOffset = &myData[0];
+            jint* targetOffset = &myData[1];
+
+            const jbyte* uSource =(jbyte*) (*env)->GetPrimitiveArrayCritical(env,source, NULL);
+            if(uSource) {
+                jchar* uTarget=(jchar*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
+                if(uTarget) {
+                    const jbyte* mySource = uSource+ *sourceOffset;
+                    const char* mySourceLimit= uSource+sourceEnd;
+                    UChar* cTarget=uTarget+ *targetOffset;
+                    const UChar* cTargetLimit=uTarget+targetEnd;
+                    
+                    ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource,
+                                   mySourceLimit,NULL,(UBool) flush, &errorCode);
+                
+                    *sourceOffset = mySource - uSource - *sourceOffset  ;
+                    *targetOffset = cTarget - uTarget - *targetOffset;
+                    if(U_FAILURE(errorCode)) {
+                        (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+                        (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0);
+                        (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+                        return errorCode;
+                    }
+                }else{
+                    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+                }
+                (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+            }else{
+                errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+            }
+            (*env)->ReleasePrimitiveArrayCritical(env,source,(jchar*)uSource,0); 
+        }else{
+            errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+        return errorCode;
+    }
+    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+    return errorCode;
+}
+
+static jint decode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source, jint sourceEnd, jcharArray target, jint targetEnd, jintArray data, jboolean flush) {
+
+    jint ec = convertByteToChar(env, jClass,handle,source,sourceEnd, target,targetEnd,data,flush);
+
+    jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+    UConverter* cnv = (UConverter*)handle;
+
+    if(myData && cnv) {
+        UErrorCode errorCode = U_ZERO_ERROR;
+        myData[3] = ucnv_toUCountPending(cnv, &errorCode);
+
+        if(ec == U_ILLEGAL_CHAR_FOUND || ec == U_INVALID_CHAR_FOUND ) {
+            char invalidChars[32] = {'\0'};
+            int8_t len = 32;
+            ucnv_getInvalidChars(cnv,invalidChars,&len,&errorCode);
+            
+            if(U_SUCCESS(errorCode)) {
+                myData[2] = len;
+            }	  
+        }
+    }
+    (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+    return ec;
+}
+static void resetByteToChar(JNIEnv *env, jclass jClass, jlong handle) {
+
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+        ucnv_resetToUnicode(cnv);
+    }
+}
+
+static void resetCharToByte(JNIEnv *env, jclass jClass, jlong handle) {
+
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+        ucnv_resetFromUnicode(cnv);
+    }
+
+}
+
+static jint countInvalidBytes (JNIEnv *env, jclass jClass, jlong handle, jintArray length) {
+
+    UConverter* cnv = (UConverter*)handle;
+    UErrorCode errorCode = U_ZERO_ERROR;
+    if(cnv) {
+        char invalidChars[32];
+
+        jint* len = (jint*) (*env)->GetPrimitiveArrayCritical(env,length, NULL);
+        if(len) {
+            ucnv_getInvalidChars(cnv,invalidChars,(int8_t*)len,&errorCode);
+        }
+        (*env)->ReleasePrimitiveArrayCritical(env,length,(jint*)len,0);
+        return errorCode;
+    }
+    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+    return errorCode;
+
+}
+
+
+static jint countInvalidChars(JNIEnv *env, jclass jClass, jlong handle, jintArray length) {
+
+    UErrorCode errorCode =U_ZERO_ERROR;
+    UConverter* cnv = (UConverter*)handle;
+    UChar invalidUChars[32];
+    if(cnv) {
+        jint* len = (jint*) (*env)->GetPrimitiveArrayCritical(env,length, NULL);
+        if(len) {
+            ucnv_getInvalidUChars(cnv,invalidUChars,(int8_t*)len,&errorCode);
+        }
+        (*env)->ReleasePrimitiveArrayCritical(env,length,(jint*)len,0);
+        return errorCode;
+    }
+    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+    return errorCode;
+
+}
+
+static jint getMaxBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) {
+
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+        return (jint)ucnv_getMaxCharSize(cnv);
+    }
+    return -1;
+}
+
+static jint getMinBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) {
+
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+        return (jint)ucnv_getMinCharSize(cnv);
+    }
+    return -1;
+}
+static jfloat getAveBytesPerChar(JNIEnv *env, jclass jClass, jlong handle) {
+
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+         jfloat max = (jfloat)ucnv_getMaxCharSize(cnv);
+         jfloat min = (jfloat)ucnv_getMinCharSize(cnv);
+         return (jfloat) ( (max+min)/2 );
+    }
+    return -1;
+}
+static jint flushByteToChar(JNIEnv *env, jclass jClass,jlong handle, jcharArray target, jint targetEnd, jintArray data) {
+
+    UErrorCode errorCode =U_ZERO_ERROR;
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+        jbyte source ='\0';
+        jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+        if(myData) {
+            jint* targetOffset = &myData[1];
+            jchar* uTarget=(jchar*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
+            if(uTarget) {
+                const jbyte* mySource =&source;
+                const char* mySourceLimit=&source;
+                UChar* cTarget=uTarget+ *targetOffset;
+                const UChar* cTargetLimit=uTarget+targetEnd;
+
+                ucnv_toUnicode( cnv , &cTarget, cTargetLimit,(const char**)&mySource,
+                               mySourceLimit,NULL,TRUE, &errorCode);
+
+
+                *targetOffset = (jint) ((jchar*)cTarget - uTarget)- *targetOffset;
+                if(U_FAILURE(errorCode)) {
+                    (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+                    (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+                    return errorCode;
+                }
+            }else{
+                errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+            }
+            (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+
+        }else{
+            errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+        return errorCode;
+    }
+    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+    return errorCode;
+}
+
+static jint flushCharToByte (JNIEnv *env, jclass jClass, jlong handle, jbyteArray target, jint targetEnd, jintArray data) {
+          
+    UErrorCode errorCode =U_ZERO_ERROR;
+    UConverter* cnv = (UConverter*)handle;
+    jchar source = '\0';
+    if(cnv) {
+        jint* myData = (jint*) (*env)->GetPrimitiveArrayCritical(env,data,NULL);
+        if(myData) {
+            jint* targetOffset = &myData[1];
+            jbyte* uTarget=(jbyte*) (*env)->GetPrimitiveArrayCritical(env,target,NULL);
+            if(uTarget) {
+                const jchar* mySource = &source;
+                const UChar* mySourceLimit= &source;
+                char* cTarget=uTarget+ *targetOffset;
+                const char* cTargetLimit=uTarget+targetEnd;
+
+                ucnv_fromUnicode( cnv , &cTarget, cTargetLimit,&mySource,
+                                  mySourceLimit,NULL,TRUE, &errorCode);
+            
+
+                *targetOffset = (jint) ((jbyte*)cTarget - uTarget)- *targetOffset;
+                if(U_FAILURE(errorCode)) {
+                    (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+                
+                    (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+                    return errorCode;
+                }
+            }else{
+                errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+            }
+            (*env)->ReleasePrimitiveArrayCritical(env,target,uTarget,0);
+        }else{
+            errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        (*env)->ReleasePrimitiveArrayCritical(env,data,(jint*)myData,0);
+        return errorCode;
+    }
+    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+    return errorCode;
+}
+
+void toChars(const UChar* us, char* cs, int32_t length) {
+    UChar u;
+    while(length>0) {
+        u=*us++;
+        *cs++=(char)u;
+        --length;
+    }
+}
+static jint setSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle, jbyteArray subChars, jint length) {
+
+    UConverter* cnv = (UConverter*) handle;
+    UErrorCode errorCode = U_ZERO_ERROR;
+    if(cnv) {
+        jbyte* u_subChars = (*env)->GetPrimitiveArrayCritical(env,subChars,NULL);
+        if(u_subChars) {
+             char* mySubChars= (char*)malloc(sizeof(char)*length);
+             toChars((UChar*)u_subChars,&mySubChars[0],length);
+             ucnv_setSubstChars(cnv,mySubChars, (char)length,&errorCode);
+             if(U_FAILURE(errorCode)) {
+                (*env)->ReleasePrimitiveArrayCritical(env,subChars,mySubChars,0);
+                return errorCode;
+             }
+             free(mySubChars);
+        }
+        else{   
+           errorCode =  U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        (*env)->ReleasePrimitiveArrayCritical(env,subChars,u_subChars,0); 
+        return errorCode;
+    }
+    errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+    return errorCode;
+}
+
+
+#define VALUE_STRING_LENGTH 32
+
+typedef struct{
+    int length;
+    UChar subChars[256];
+    UBool stopOnIllegal;
+}SubCharStruct;
+
+
+static UErrorCode 
+setToUCallbackSubs(UConverter* cnv,UChar* subChars, int32_t length,UBool stopOnIllegal ) {
+    SubCharStruct* substitutionCharS = (SubCharStruct*) malloc(sizeof(SubCharStruct));
+    UErrorCode errorCode = U_ZERO_ERROR;
+    if(substitutionCharS) {
+       UConverterToUCallback toUOldAction;
+       void* toUOldContext=NULL;
+       void* toUNewContext=NULL ;
+       if(subChars) {
+            u_strncpy(substitutionCharS->subChars,subChars,length);
+       }else{
+           substitutionCharS->subChars[length++] =0xFFFD;
+       }
+       substitutionCharS->subChars[length]=0;
+       substitutionCharS->length = length;
+       substitutionCharS->stopOnIllegal = stopOnIllegal;
+       toUNewContext = substitutionCharS;
+
+       ucnv_setToUCallBack(cnv,
+           JNI_TO_U_CALLBACK_SUBSTITUTE,
+           toUNewContext,
+           &toUOldAction,
+           (const void**)&toUOldContext,
+           &errorCode);
+
+       if(toUOldContext) {
+           SubCharStruct* temp = (SubCharStruct*) toUOldContext;
+           free(temp);
+       }
+
+       return errorCode;
+    }
+    return U_MEMORY_ALLOCATION_ERROR;
+}
+static jint setSubstitutionChars(JNIEnv *env, jclass jClass, jlong handle, jcharArray subChars, jint length) {
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    UConverter* cnv = (UConverter*) handle;
+    jchar* u_subChars=NULL;
+    if(cnv) {
+        if(subChars) {
+            int len = (*env)->GetArrayLength(env,subChars);
+            u_subChars = (*env)->GetPrimitiveArrayCritical(env,subChars,NULL);
+            if(u_subChars) {
+               errorCode =  setToUCallbackSubs(cnv,u_subChars,len,FALSE);
+            }else{
+                errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+            }
+            (*env)->ReleasePrimitiveArrayCritical(env,subChars,u_subChars,0);
+            return errorCode;
+        }
+    }
+    return U_ILLEGAL_ARGUMENT_ERROR;
+}
+
+
+void  JNI_TO_U_CALLBACK_SUBSTITUTE( const void *context, UConverterToUnicodeArgs *toArgs, const char* codeUnits, int32_t length, UConverterCallbackReason reason, UErrorCode * err) {
+
+    if(context) {
+        SubCharStruct* temp = (SubCharStruct*)context;
+        if( temp) {
+            if(temp->stopOnIllegal==FALSE) {
+                if (reason > UCNV_IRREGULAR) {
+                    return;
+                }
+                /* reset the error */
+                *err = U_ZERO_ERROR;
+                ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err);
+            }else{
+                if(reason != UCNV_UNASSIGNED) {
+                    /* the caller must have set 
+                     * the error code accordingly
+                     */
+                    return;
+                }else{
+                    *err = U_ZERO_ERROR;
+                    ucnv_cbToUWriteUChars(toArgs,temp->subChars ,temp->length , 0, err);
+                    return;
+                }
+            }
+        }
+    }
+    return;
+}
+
+static jboolean canEncode(JNIEnv *env, jclass jClass, jlong handle, jint codeUnit) {
+    
+    UErrorCode errorCode =U_ZERO_ERROR;
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+        UChar source[3];
+        UChar *mySource=source;
+        const UChar* sourceLimit = (codeUnit<0x010000) ? &source[1] : &source[2];
+        char target[5];
+        char *myTarget = target;
+        const char* targetLimit = &target[4];
+        int i=0;
+        UTF_APPEND_CHAR(&source[0],i,2,codeUnit);
+
+        ucnv_fromUnicode(cnv,&myTarget,targetLimit, 
+                         (const UChar**)&mySource, 
+                         sourceLimit,NULL, TRUE,&errorCode);
+
+        if(U_SUCCESS(errorCode)) {
+            return (jboolean)TRUE;
+        }
+    }
+    return (jboolean)FALSE;
+}
+
+
+static jboolean canDecode(JNIEnv *env, jclass jClass, jlong handle, jbyteArray source) {
+    
+    UErrorCode errorCode =U_ZERO_ERROR;
+    UConverter* cnv = (UConverter*)handle;
+    if(cnv) {
+        jint len = (*env)->GetArrayLength(env,source);    
+        jbyte* cSource =(jbyte*) (*env)->GetPrimitiveArrayCritical(env,source, NULL);
+        if(cSource) {
+            const jbyte* cSourceLimit = cSource+len;
+
+            /* Assume that we need at most twice the length of source */
+            UChar* target = (UChar*) malloc(sizeof(UChar)* (len<<1));
+            UChar* targetLimit = target + (len<<1);
+            if(target) {
+                ucnv_toUnicode(cnv,&target,targetLimit, 
+                               (const char**)&cSource, 
+                               cSourceLimit,NULL, TRUE,&errorCode);
+
+                if(U_SUCCESS(errorCode)) {
+                    free(target);
+                    (*env)->ReleasePrimitiveArrayCritical(env,source,cSource,0);        
+                    return (jboolean)TRUE;
+                }
+            }
+            free(target);
+        }
+        (*env)->ReleasePrimitiveArrayCritical(env,source,cSource,0);        
+    }
+    return (jboolean)FALSE;
+}
+
+static jint countAvailable(JNIEnv *env, jclass jClass) {
+    return ucnv_countAvailable();
+}
+
+int32_t copyString(char* dest, int32_t destCapacity, int32_t startIndex,
+           const char* src, UErrorCode* status) {
+    int32_t srcLen = 0, i=0;
+    if(U_FAILURE(*status)) {
+        return 0;
+    }
+    if(dest == NULL || src == NULL || destCapacity < startIndex) { 
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    srcLen = strlen(src);
+    if(srcLen >= destCapacity) {
+        *status = U_BUFFER_OVERFLOW_ERROR;
+        return 0;
+    }
+    for(i=0; i < srcLen; i++) {
+        dest[startIndex++] = src[i];
+    }
+    /* null terminate the buffer */
+    dest[startIndex] = 0; /* no bounds check already made sure that we have enough room */
+    return startIndex;
+}
+
+int32_t getJavaCanonicalName1(const char* icuCanonicalName, 
+                     char* canonicalName, int32_t capacity, 
+                     UErrorCode* status) {
+ /*
+ If a charset listed in the IANA Charset Registry is supported by an implementation 
+ of the Java platform then its canonical name must be the name listed in the registry. 
+ Many charsets are given more than one name in the registry, in which case the registry 
+ identifies one of the names as MIME-preferred. If a charset has more than one registry 
+ name then its canonical name must be the MIME-preferred name and the other names in 
+ the registry must be valid aliases. If a supported charset is not listed in the IANA 
+ registry then its canonical name must begin with one of the strings "X-" or "x-".
+ */
+    int32_t retLen = 0;
+    const char* cName = NULL;
+    /* find out the alias with MIME tag */
+    if((cName =ucnv_getStandardName(icuCanonicalName, "MIME", status)) !=  NULL) {
+        retLen = copyString(canonicalName, capacity, 0, cName, status);
+        /* find out the alias with IANA tag */
+    }else if((cName =ucnv_getStandardName(icuCanonicalName, "IANA", status)) !=  NULL) {
+        retLen = copyString(canonicalName, capacity, 0, cName, status);
+    }else {
+        /*  
+            check to see if an alias already exists with x- prefix, if yes then 
+            make that the canonical name
+        */
+        int32_t aliasNum = ucnv_countAliases(icuCanonicalName,status);
+        int32_t i=0;
+        const char* name;
+        for(i=0;i<aliasNum;i++) {
+            name = ucnv_getAlias(icuCanonicalName,(uint16_t)i, status);
+            if(name != NULL && name[0]=='x' && name[1]=='-') {
+                retLen = copyString(canonicalName, capacity, 0, name, status);
+                break;
+            }
+        }
+        /* last resort just append x- to any of the alias and 
+            make it the canonical name */
+        if(retLen == 0 && U_SUCCESS(*status)) {
+            name = ucnv_getStandardName(icuCanonicalName, "UTR22", status);
+            if(name == NULL && strchr(icuCanonicalName, ',')!= NULL) {
+                name = ucnv_getAlias(icuCanonicalName, 1, status);
+                if(*status == U_INDEX_OUTOFBOUNDS_ERROR) {
+                    *status = U_ZERO_ERROR;
+                }
+            }
+            /* if there is no UTR22 canonical name .. then just return itself*/
+            if(name == NULL) {                
+                name = icuCanonicalName;
+            }
+            if(capacity >= 2) {
+                strcpy(canonicalName,"x-");
+            }
+            retLen = copyString(canonicalName, capacity, 2, name, status);
+        }
+    }
+    return retLen;
+}
+
+static jobjectArray getAvailable(JNIEnv *env, jclass jClass) {
+   
+    jobjectArray ret;
+    int32_t i = 0;
+    int32_t num = ucnv_countAvailable();
+    UErrorCode error = U_ZERO_ERROR;
+    const char* name =NULL;
+    char canonicalName[256]={0};
+    ret= (jobjectArray)(*env)->NewObjectArray( env,num,
+                                               (*env)->FindClass(env,"java/lang/String"),
+                                               (*env)->NewStringUTF(env,""));
+
+    for(i=0;i<num;i++) {
+        name = ucnv_getAvailableName(i);
+        getJavaCanonicalName1(name, canonicalName, 256, &error);   
+#if DEBUG
+        if(U_FAILURE(error)) {
+            printf("An error occurred retrieving index %i. Error: %s. \n", i, u_errorName(error));
+        }
+
+        printf("canonical name for %s\n", canonicalName);
+#endif        
+        (*env)->SetObjectArrayElement(env,ret,i,(*env)->NewStringUTF(env,canonicalName));
+         /*printf("canonical name : %s  at %i\n", name,i); */
+        canonicalName[0]='\0';/* nul terminate */
+    }
+    return (ret);
+}
+
+static jint countAliases(JNIEnv *env, jclass jClass,jstring enc) {
+    
+    UErrorCode error = U_ZERO_ERROR;
+    jint num =0;
+    const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
+    
+    if(encName) {
+        num = ucnv_countAliases(encName,&error);
+    }
+    
+    (*env)->ReleaseStringUTFChars(env,enc,encName);
+
+    return num;
+}
+
+
+static jobjectArray getAliases(JNIEnv *env, jclass jClass, jstring enc) {
+
+    jobjectArray ret=NULL;
+    int32_t aliasNum = 0;
+    UErrorCode error = U_ZERO_ERROR;
+    const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
+    int i=0;
+    int j=0;
+    const char* aliasArray[50];
+    // BEGIN android-removed
+    // int32_t utf16AliasNum = 0; 
+    // END android-removed
+
+    
+    if(encName) {
+        const char* myEncName = encName;
+        aliasNum = ucnv_countAliases(myEncName,&error);
+
+        // BEGIN android-removed
+        // /* special case for UTF-16. In java UTF-16 is always BE*/ 
+        // if(strcmp(myEncName, UTF_16BE)==0) { 
+        //     utf16AliasNum=ucnv_countAliases(UTF_16,&error); 
+        // }
+        // END android-removed
+
+        if(aliasNum==0 && encName[0] == 0x78 /*x*/ && encName[1]== 0x2d /*-*/) {
+            myEncName = encName+2;
+            aliasNum = ucnv_countAliases(myEncName,&error);
+        }
+        if(U_SUCCESS(error)) {
+            for(i=0,j=0;i<aliasNum;i++) {
+                const char* name = ucnv_getAlias(myEncName,(uint16_t)i,&error);
+                if(strchr(name,'+')==0 && strchr(name,',')==0) {
+                    aliasArray[j++]= name;
+                }
+            }
+
+            // BEGIN android-removed
+            // if(utf16AliasNum>0) {
+            //     for(i=0;i<utf16AliasNum;i++) {
+            //         const char* name = ucnv_getAlias(UTF_16,(uint16_t)i,&error);
+            //         if(strchr(name,'+')==0 && strchr(name,',')==0) {
+            //             aliasArray[j++]= name;
+            //         }
+            //     }
+            // }
+            // END android-removed
+
+            ret =  (jobjectArray)(*env)->NewObjectArray(env,j,
+                                                        (*env)->FindClass(env,"java/lang/String"),
+                                                        (*env)->NewStringUTF(env,""));
+            for(;--j>=0;) {
+                 (*env)->SetObjectArrayElement(env,ret,j,(*env)->NewStringUTF(env,aliasArray[j]));
+            }
+        }            
+    }
+    (*env)->ReleaseStringUTFChars(env,enc,encName);
+
+    return (ret);
+}
+
+static jstring getCanonicalName(JNIEnv *env, jclass jClass,jstring enc) {
+
+    UErrorCode error = U_ZERO_ERROR;
+    const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
+    const char* canonicalName = "";
+    jstring ret;
+    if(encName) {
+        canonicalName = ucnv_getAlias(encName,0,&error);
+        if(canonicalName !=NULL && strstr(canonicalName,",")!=0) {
+            canonicalName = ucnv_getAlias(canonicalName,1,&error);
+        }
+        ret = ((*env)->NewStringUTF(env, canonicalName));
+    }
+    (*env)->ReleaseStringUTFChars(env,enc,encName);
+    return ret;
+}
+
+static jstring getICUCanonicalName(JNIEnv *env, jclass jClass, jstring enc) {
+
+    UErrorCode error = U_ZERO_ERROR;
+    const char* encName = (*env)->GetStringUTFChars(env,enc,NULL);
+    const char* canonicalName = NULL;
+    jstring ret = NULL;
+    if(encName) {
+        // BEGIN android-removed
+        // if(strcmp(encName,"UTF-16")==0) {
+        //     ret = ((*env)->NewStringUTF(env,UTF_16BE));
+        // }else
+        // END android-removed
+        if((canonicalName = ucnv_getCanonicalName(encName, "MIME", &error))!=NULL) {
+            ret = ((*env)->NewStringUTF(env, canonicalName));
+        }else if((canonicalName = ucnv_getCanonicalName(encName, "IANA", &error))!=NULL) {
+            ret = ((*env)->NewStringUTF(env, canonicalName));
+        }else if((canonicalName = ucnv_getCanonicalName(encName, "", &error))!=NULL) {
+            ret = ((*env)->NewStringUTF(env, canonicalName));
+        }else if((canonicalName =  ucnv_getAlias(encName, 0, &error)) != NULL) {
+            /* we have some aliases in the form x-blah .. match those first */
+            ret = ((*env)->NewStringUTF(env, canonicalName));
+        }else if( ret ==NULL && strstr(encName, "x-") == encName) {
+            /* check if the converter can be opened with the encName given */
+            UConverter* conv = NULL;
+            error = U_ZERO_ERROR;
+            conv = ucnv_open(encName+2, &error);
+            if(conv!=NULL) {
+                ret = ((*env)->NewStringUTF(env, encName+2));
+            }else{
+                /* unsupported encoding */
+                ret = ((*env)->NewStringUTF(env, ""));
+            }
+            ucnv_close(conv);
+        }else{
+            /* unsupported encoding */
+           ret = ((*env)->NewStringUTF(env, ""));
+        }
+    }
+    (*env)->ReleaseStringUTFChars(env,enc,encName);
+    return ret;
+}
+
+static jstring getJavaCanonicalName2(JNIEnv *env, jclass jClass, jstring icuCanonName) {
+ /*
+ If a charset listed in the IANA Charset Registry is supported by an implementation 
+ of the Java platform then its canonical name must be the name listed in the registry. 
+ Many charsets are given more than one name in the registry, in which case the registry 
+ identifies one of the names as MIME-preferred. If a charset has more than one registry 
+ name then its canonical name must be the MIME-preferred name and the other names in 
+ the registry must be valid aliases. If a supported charset is not listed in the IANA 
+ registry then its canonical name must begin with one of the strings "X-" or "x-".
+ */
+    UErrorCode error = U_ZERO_ERROR;
+    const char* icuCanonicalName = (*env)->GetStringUTFChars(env,icuCanonName,NULL);
+    char cName[UCNV_MAX_CONVERTER_NAME_LENGTH] = {0};
+    jstring ret;
+    if(icuCanonicalName && icuCanonicalName[0] != 0) {
+        getJavaCanonicalName1(icuCanonicalName, cName, UCNV_MAX_CONVERTER_NAME_LENGTH, &error);
+    }
+    ret = ((*env)->NewStringUTF(env, cName));
+    (*env)->ReleaseStringUTFChars(env,icuCanonName,icuCanonicalName);
+    return ret;
+}
+
+#define SUBS_ARRAY_CAPACITY 256
+typedef struct{
+    int length;
+    char subChars[SUBS_ARRAY_CAPACITY];
+    UConverterFromUCallback onUnmappableInput;
+    UConverterFromUCallback onMalformedInput;
+}EncoderCallbackContext;
+
+void CHARSET_ENCODER_CALLBACK(const void *context,
+                  UConverterFromUnicodeArgs *fromArgs,
+                  const UChar* codeUnits,
+                  int32_t length,
+                  UChar32 codePoint,
+                  UConverterCallbackReason reason,
+                  UErrorCode * status) {   
+    if(context) {
+        EncoderCallbackContext* ctx = (EncoderCallbackContext*)context;
+        
+        if(ctx) {
+            UConverterFromUCallback realCB = NULL;
+            switch(reason) {
+                case UCNV_UNASSIGNED:
+                    realCB = ctx->onUnmappableInput;
+                    break;
+                case UCNV_ILLEGAL:/*malformed input*/
+                case UCNV_IRREGULAR:/*malformed input*/
+                    realCB = ctx->onMalformedInput;
+                    break;
+                /*
+                case UCNV_RESET:
+                    ucnv_resetToUnicode(args->converter);
+                    break;
+                case UCNV_CLOSE:
+                    ucnv_close(args->converter);
+                    break;
+                case UCNV_CLONE:
+                    ucnv_clone(args->clone);
+               */
+                default:
+                    *status = U_ILLEGAL_ARGUMENT_ERROR;
+                    return;
+            }
+            if(realCB==NULL) {
+                *status = U_INTERNAL_PROGRAM_ERROR;
+            }
+            realCB(context, fromArgs, codeUnits, length, codePoint, reason, status);
+        }
+    }      
+}
+
+void JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER(const void *context,
+                                        UConverterFromUnicodeArgs *fromArgs,
+                                        const UChar* codeUnits,
+                                        int32_t length,
+                                        UChar32 codePoint,
+                                        UConverterCallbackReason reason,
+                                        UErrorCode * err) {
+    if(context) {
+        EncoderCallbackContext* temp = (EncoderCallbackContext*)context;
+        *err = U_ZERO_ERROR;
+        ucnv_cbFromUWriteBytes(fromArgs,temp->subChars ,temp->length , 0, err);
+    }
+    return;
+}
+
+UConverterFromUCallback getFromUCallback(int32_t mode) {
+    switch(mode) {
+        default: /* falls through */
+        case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK:
+            return UCNV_FROM_U_CALLBACK_STOP;
+        case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK:
+            return UCNV_FROM_U_CALLBACK_SKIP ;
+        case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK:
+            return JNI_FROM_U_CALLBACK_SUBSTITUTE_ENCODER;
+    }
+}
+
+static jint setCallbackEncode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jbyteArray subChars, jint length) {
+
+    UConverter* conv = (UConverter*)handle;
+    UErrorCode errorCode =U_ZERO_ERROR;
+
+    if(conv) {
+        
+        UConverterFromUCallback fromUOldAction = NULL;
+        void* fromUOldContext = NULL;
+        EncoderCallbackContext* fromUNewContext=NULL;
+        UConverterFromUCallback fromUNewAction=NULL;
+        jbyte* sub = (jbyte*) (*env)->GetPrimitiveArrayCritical(env,subChars, NULL);
+        ucnv_getFromUCallBack(conv, &fromUOldAction, &fromUOldContext);
+
+        /* fromUOldContext can only be DecodeCallbackContext since
+           the converter created is private data for the decoder
+           and callbacks can only be set via this method!
+        */
+        if(fromUOldContext==NULL) {
+            fromUNewContext = (EncoderCallbackContext*) malloc(sizeof(EncoderCallbackContext));
+            fromUNewAction = CHARSET_ENCODER_CALLBACK;
+        }else{
+            fromUNewContext = fromUOldContext;
+            fromUNewAction = fromUOldAction;
+            fromUOldAction = NULL;
+            fromUOldContext = NULL;
+        }
+        fromUNewContext->onMalformedInput = getFromUCallback(onMalformedInput);
+        fromUNewContext->onUnmappableInput = getFromUCallback(onUnmappableInput);
+        if(sub!=NULL) {
+            fromUNewContext->length = length;
+            strncpy(fromUNewContext->subChars, sub, length);
+        }else{
+            errorCode = U_ILLEGAL_ARGUMENT_ERROR;
+        }
+
+        (*env)->ReleasePrimitiveArrayCritical(env,subChars, NULL, 0);
+
+        ucnv_setFromUCallBack(conv,
+           fromUNewAction,
+           fromUNewContext,
+           &fromUOldAction,
+           (const void**)&fromUOldContext,
+           &errorCode);
+
+
+        return errorCode;
+    }
+    return U_ILLEGAL_ARGUMENT_ERROR;
+}
+                                                                  
+typedef struct{
+    int length;
+    UChar subUChars[256];
+    UConverterToUCallback onUnmappableInput;
+    UConverterToUCallback onMalformedInput;
+}DecoderCallbackContext;
+
+void JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER(const void *context,
+                                    UConverterToUnicodeArgs *toArgs,
+                                    const char* codeUnits,
+                                    int32_t length,
+                                    UConverterCallbackReason reason,
+                                    UErrorCode * err) {
+    if(context) {
+        DecoderCallbackContext* temp = (DecoderCallbackContext*)context;
+        *err = U_ZERO_ERROR;
+        ucnv_cbToUWriteUChars(toArgs,temp->subUChars ,temp->length , 0, err);
+    }
+    return;
+}
+
+UConverterToUCallback getToUCallback(int32_t mode) {
+    switch(mode) {
+        default: /* falls through */
+        case com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK:
+            return UCNV_TO_U_CALLBACK_STOP;
+        case com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK:
+            return UCNV_TO_U_CALLBACK_SKIP ;
+        case com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK:
+            return JNI_TO_U_CALLBACK_SUBSTITUTE_DECODER;
+    }
+}
+
+void  CHARSET_DECODER_CALLBACK(const void *context,
+                               UConverterToUnicodeArgs *args, 
+                               const char* codeUnits, 
+                               int32_t length,
+                               UConverterCallbackReason reason,
+                               UErrorCode *status ) {
+   
+    if(context) {
+        DecoderCallbackContext* ctx = (DecoderCallbackContext*)context;
+        
+        if(ctx) {
+            UConverterToUCallback realCB = NULL;
+            switch(reason) {
+                case UCNV_UNASSIGNED:
+                    realCB = ctx->onUnmappableInput;
+                    break;
+                case UCNV_ILLEGAL:/*malformed input*/
+                case UCNV_IRREGULAR:/*malformed input*/
+                    realCB = ctx->onMalformedInput;
+                    break;
+                /*
+                case UCNV_RESET:
+                    ucnv_resetToUnicode(args->converter);
+                    break;
+                case UCNV_CLOSE:
+                    ucnv_close(args->converter);
+                    break;
+                case UCNV_CLONE:
+                    ucnv_clone(args->clone);
+               */
+                default:
+                    *status = U_ILLEGAL_ARGUMENT_ERROR;
+                    return;
+            }
+            if(realCB==NULL) {
+                *status = U_INTERNAL_PROGRAM_ERROR;
+            }
+            realCB(context, args, codeUnits, length, reason, status);
+        }
+    }      
+}
+
+static jint setCallbackDecode(JNIEnv *env, jclass jClass, jlong handle, jint onMalformedInput, jint onUnmappableInput, jcharArray subChars, jint length) {
+    
+    UConverter* conv = (UConverter*)handle;
+    UErrorCode errorCode =U_ZERO_ERROR;
+    if(conv) {
+        
+        UConverterToUCallback toUOldAction ;
+        void* toUOldContext;
+        DecoderCallbackContext* toUNewContext = NULL;
+        UConverterToUCallback toUNewAction = NULL;
+        jchar* sub = (jchar*) (*env)->GetPrimitiveArrayCritical(env,subChars, NULL);
+    
+        ucnv_getToUCallBack(conv, &toUOldAction, &toUOldContext);
+
+        /* toUOldContext can only be DecodeCallbackContext since
+           the converter created is private data for the decoder
+           and callbacks can only be set via this method!
+        */
+        if(toUOldContext==NULL) {
+            toUNewContext = (DecoderCallbackContext*) malloc(sizeof(DecoderCallbackContext));
+            toUNewAction = CHARSET_DECODER_CALLBACK;
+        }else{
+            toUNewContext = toUOldContext;
+            toUNewAction = toUOldAction;
+            toUOldAction = NULL;
+            toUOldContext = NULL;
+        }
+        toUNewContext->onMalformedInput = getToUCallback(onMalformedInput);
+        toUNewContext->onUnmappableInput = getToUCallback(onUnmappableInput);
+        if(sub!=NULL) {
+            toUNewContext->length = length;
+            u_strncpy(toUNewContext->subUChars, sub, length);
+        }else{
+            errorCode =  U_ILLEGAL_ARGUMENT_ERROR;
+        }
+        (*env)->ReleasePrimitiveArrayCritical(env,subChars, NULL, 0);
+        ucnv_setToUCallBack(conv,
+           toUNewAction,
+           toUNewContext,
+           &toUOldAction,
+           (const void**)&toUOldContext,
+           &errorCode);
+
+        return errorCode;
+    }
+    return U_ILLEGAL_ARGUMENT_ERROR;
+}
+
+static jlong safeClone(JNIEnv *env, jclass jClass, jlong src) {
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    jint buffersize = U_CNV_SAFECLONE_BUFFERSIZE;
+
+    UConverter* conv=NULL;
+    UErrorCode errorCode = U_ZERO_ERROR;
+    UConverter* source = (UConverter*) src;
+
+    if(source) {
+        conv = ucnv_safeClone(source, NULL, &buffersize, &errorCode);
+    }
+
+    if (icu4jni_error(env, errorCode) != FALSE) {
+        return NULL;
+    }
+
+    return conv;
+}
+
+static jint getMaxCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) {
+    /*
+     * currently we know that max number of chars per byte is 2
+     */
+    return 2;
+}
+
+static jfloat getAveCharsPerByte(JNIEnv *env, jclass jClass, jlong handle) {
+    jfloat ret = 0;
+    ret = (jfloat)( 1/(jfloat)getMaxBytesPerChar(env, jClass, handle));
+    return ret;
+}
+
+void toUChars(const char* cs, UChar* us, int32_t length) {
+    char c;
+    while(length>0) {
+        c=*cs++;
+        *us++=(char)c;
+        --length;
+    }
+}
+
+static jbyteArray getSubstitutionBytes(JNIEnv *env, jclass jClass, jlong handle) {
+
+    const UConverter * cnv = (const UConverter *) handle;
+    UErrorCode status = U_ZERO_ERROR;
+    char subBytes[10];
+    int8_t len =(char)10;
+    jbyteArray arr;
+    if(cnv) {
+        ucnv_getSubstChars(cnv,subBytes,&len,&status);
+        if(U_SUCCESS(status)) {
+            arr = ((*env)->NewByteArray(env, len));
+            if(arr) {
+                (*env)->SetByteArrayRegion(env,arr,0,len,(jbyte*)subBytes);
+            }
+            return arr;
+        }
+    }
+    return ((*env)->NewByteArray(env, 0));
+}
+
+static jboolean contains( JNIEnv *env, jclass jClass, jlong handle1, jlong handle2) {
+    UErrorCode status = U_ZERO_ERROR;
+    const UConverter * cnv1 = (const UConverter *) handle1;
+    const UConverter * cnv2 = (const UConverter *) handle2;
+    USet* set1;
+    USet* set2;
+    UBool bRet = 0;
+    
+    if(cnv1 != NULL && cnv2 != NULL) {
+	    /* open charset 1 */
+        set1 = uset_open(1, 2);
+        ucnv_getUnicodeSet(cnv1, set1, UCNV_ROUNDTRIP_SET, &status);
+
+        if(U_SUCCESS(status)) {
+            /* open charset 2 */
+            status = U_ZERO_ERROR;
+            set2 = uset_open(1, 2);
+            ucnv_getUnicodeSet(cnv2, set2, UCNV_ROUNDTRIP_SET, &status);
+
+            /* contains?      */
+            if(U_SUCCESS(status)) {
+                bRet = uset_containsAll(set1, set2);
+	            uset_close(set2);
+            }
+            uset_close(set1);
+        }
+    }
+	return bRet;
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "convertByteToChar", "(J[BI[CI[IZ)I", (void*) convertByteToChar },
+    { "decode", "(J[BI[CI[IZ)I", (void*) decode },
+    { "convertCharToByte", "(J[CI[BI[IZ)I", (void*) convertCharToByte },
+    { "encode", "(J[CI[BI[IZ)I", (void*) encode },
+    { "flushCharToByte", "(J[BI[I)I", (void*) flushCharToByte },
+    { "flushByteToChar", "(J[CI[I)I", (void*) flushByteToChar },
+    { "openConverter", "(Ljava/lang/String;)J", (void*) openConverter },
+    { "resetByteToChar", "(J)V", (void*) resetByteToChar },
+    { "resetCharToByte", "(J)V", (void*) resetCharToByte },
+    { "closeConverter", "(J)V", (void*) closeConverter },
+    { "setSubstitutionChars", "(J[CI)I", (void*) setSubstitutionChars },
+    { "setSubstitutionBytes", "(J[BI)I", (void*) setSubstitutionBytes },
+    { "setSubstitutionModeCharToByte", "(JZ)I", (void*) setSubstitutionModeCharToByte },
+    { "setSubstitutionModeByteToChar", "(JZ)I", (void*) setSubstitutionModeByteToChar },
+    { "countInvalidBytes", "(J[I)I", (void*) countInvalidBytes },
+    { "countInvalidChars", "(J[I)I", (void*) countInvalidChars },
+    { "getMaxBytesPerChar", "(J)I", (void*) getMaxBytesPerChar },
+    { "getMinBytesPerChar", "(J)I", (void*) getMinBytesPerChar },
+    { "getAveBytesPerChar", "(J)F", (void*) getAveBytesPerChar },
+    { "getMaxCharsPerByte", "(J)I", (void*) getMaxCharsPerByte },
+    { "getAveCharsPerByte", "(J)F", (void*) getAveCharsPerByte },
+    { "contains", "(JJ)Z", (void*) contains },
+    { "getSubstitutionBytes", "(J)[B", (void*) getSubstitutionBytes },
+    { "canEncode", "(JI)Z", (void*) canEncode },
+    { "canDecode", "(J[B)Z", (void*) canDecode },
+    { "countAvailable", "()I", (void*) countAvailable },
+    { "getAvailable", "()[Ljava/lang/String;", (void*) getAvailable },
+    { "countAliases", "(Ljava/lang/String;)I", (void*) countAliases },
+    { "getAliases", "(Ljava/lang/String;)[Ljava/lang/String;", (void*) getAliases },
+    { "getCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getCanonicalName },
+    { "getICUCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getICUCanonicalName },
+    { "getJavaCanonicalName", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getJavaCanonicalName2 },
+    { "setCallbackDecode", "(JII[CI)I", (void*) setCallbackDecode },
+    { "setCallbackEncode", "(JII[BI)I", (void*) setCallbackEncode },
+    { "safeClone", "(J)J", (void*) safeClone }
+};
+
+int register_com_ibm_icu4jni_converters_NativeConverter(JNIEnv *_env) {
+    return jniRegisterNativeMethods(_env, "com/ibm/icu4jni/converters/NativeConverter",
+                gMethods, NELEM(gMethods));
+}
+
+
diff --git a/libcore/icu/src/main/native/ConverterInterface.h b/libcore/icu/src/main/native/ConverterInterface.h
new file mode 100644
index 0000000..e9dbf6b
--- /dev/null
+++ b/libcore/icu/src/main/native/ConverterInterface.h
@@ -0,0 +1,299 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_ibm_icu4jni_converters_NativeConverter */
+
+#ifndef _Included_com_ibm_icu4jni_converters_NativeConverter
+#define _Included_com_ibm_icu4jni_converters_NativeConverter
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK
+#define com_ibm_icu4jni_converters_NativeConverter_STOP_CALLBACK 0L
+#undef com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK
+#define com_ibm_icu4jni_converters_NativeConverter_SKIP_CALLBACK 1L
+#undef com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK
+#define com_ibm_icu4jni_converters_NativeConverter_SUBSTITUTE_CALLBACK 2L
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    convertByteToChar
+ * Signature: (J[BI[CI[IZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_convertByteToChar
+  (JNIEnv *, jclass, jlong, jbyteArray, jint, jcharArray, jint, jintArray, jboolean);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    decode
+ * Signature: (J[BI[CI[IZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_decode
+  (JNIEnv *, jclass, jlong, jbyteArray, jint, jcharArray, jint, jintArray, jboolean);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    convertCharToByte
+ * Signature: (J[CI[BI[IZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_convertCharToByte
+  (JNIEnv *, jclass, jlong, jcharArray, jint, jbyteArray, jint, jintArray, jboolean);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    encode
+ * Signature: (J[CI[BI[IZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_encode
+  (JNIEnv *, jclass, jlong, jcharArray, jint, jbyteArray, jint, jintArray, jboolean);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    flushCharToByte
+ * Signature: (J[BI[I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_flushCharToByte
+  (JNIEnv *, jclass, jlong, jbyteArray, jint, jintArray);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    flushByteToChar
+ * Signature: (J[CI[I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_flushByteToChar
+  (JNIEnv *, jclass, jlong, jcharArray, jint, jintArray);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    openConverter
+ * Signature: ([JLjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_openConverter
+  (JNIEnv *, jclass, jlongArray, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    resetByteToChar
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_resetByteToChar
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    resetCharToByte
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_resetCharToByte
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    closeConverter
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_closeConverter
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    setSubstitutionChars
+ * Signature: (J[CI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setSubstitutionChars
+  (JNIEnv *, jclass, jlong, jcharArray, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    setSubstitutionBytes
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setSubstitutionBytes
+  (JNIEnv *, jclass, jlong, jbyteArray, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    setSubstitutionModeCharToByte
+ * Signature: (JZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setSubstitutionModeCharToByte
+  (JNIEnv *, jclass, jlong, jboolean);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    setSubstitutionModeByteToChar
+ * Signature: (JZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setSubstitutionModeByteToChar
+  (JNIEnv *, jclass, jlong, jboolean);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    countInvalidBytes
+ * Signature: (J[I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_countInvalidBytes
+  (JNIEnv *, jclass, jlong, jintArray);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    countInvalidChars
+ * Signature: (J[I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_countInvalidChars
+  (JNIEnv *, jclass, jlong, jintArray);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getMaxBytesPerChar
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getMaxBytesPerChar
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getMinBytesPerChar
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getMinBytesPerChar
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getAveBytesPerChar
+ * Signature: (J)F
+ */
+JNIEXPORT jfloat JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getAveBytesPerChar
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getMaxCharsPerByte
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getMaxCharsPerByte
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getAveCharsPerByte
+ * Signature: (J)F
+ */
+JNIEXPORT jfloat JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getAveCharsPerByte
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    contains
+ * Signature: (JJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_contains
+  (JNIEnv *, jclass, jlong, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getSubstitutionBytes
+ * Signature: (J)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getSubstitutionBytes
+  (JNIEnv *, jclass, jlong);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    canEncode
+ * Signature: (JI)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_canEncode
+  (JNIEnv *, jclass, jlong, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    canDecode
+ * Signature: (J[B)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_canDecode
+  (JNIEnv *, jclass, jlong, jbyteArray);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    countAvailable
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_countAvailable
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getAvailable
+ * Signature: ()[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getAvailable
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    countAliases
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_countAliases
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getAliases
+ * Signature: (Ljava/lang/String;)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getAliases
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getCanonicalName
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getCanonicalName
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getICUCanonicalName
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getICUCanonicalName
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    getJavaCanonicalName
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_getJavaCanonicalName
+  (JNIEnv *, jclass, jstring);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    setCallbackDecode
+ * Signature: (JII[CI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setCallbackDecode
+  (JNIEnv *, jclass, jlong, jint, jint, jcharArray, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    setCallbackEncode
+ * Signature: (JII[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_setCallbackEncode
+  (JNIEnv *, jclass, jlong, jint, jint, jbyteArray, jint);
+
+/*
+ * Class:     com_ibm_icu4jni_converters_NativeConverter
+ * Method:    safeClone
+ * Signature: (J[J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ibm_icu4jni_converters_NativeConverter_safeClone
+  (JNIEnv *, jclass, jlong, jlongArray);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/libcore/icu/src/main/native/DecimalFormatInterface.cpp b/libcore/icu/src/main/native/DecimalFormatInterface.cpp
new file mode 100644
index 0000000..b87cbb7
--- /dev/null
+++ b/libcore/icu/src/main/native/DecimalFormatInterface.cpp
@@ -0,0 +1,822 @@
+/*
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Internal native functions.  All of the functions defined here make
+ * direct use of VM functions or data structures, so they can't be written
+ * with JNI and shouldn't really be in a shared library.
+ *
+ * All functions here either complete quickly or are used to enter a wait
+ * state, so we don't set the thread status to THREAD_NATIVE when executing
+ * these methods.  This means that the GC will wait for these functions
+ * to finish.  DO NOT perform long operations or blocking I/O in here.
+ *
+ * In some cases we're following the division of labor defined by GNU
+ * ClassPath, e.g. java.lang.Thread has "Thread" and "VMThread", with
+ * the VM-specific behavior isolated in VMThread.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/unum.h"
+#include "unicode/numfmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/fmtable.h"
+#include "unicode/ustring.h"
+#include "digitlst.h"
+#include "ErrorCode.h"
+#include <stdlib.h>
+#include <string.h>
+#include "cutils/log.h"
+
+static UBool icuError(JNIEnv *env, UErrorCode errorcode)
+{
+    const char *emsg = u_errorName(errorcode);
+    jclass  exception;
+
+    if (U_FAILURE(errorcode)) {// errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
+        switch (errorcode) {
+            case U_ILLEGAL_ARGUMENT_ERROR :
+                exception = env->FindClass("java/lang/IllegalArgumentException");
+                break;
+            case U_INDEX_OUTOFBOUNDS_ERROR :
+            case U_BUFFER_OVERFLOW_ERROR :
+                exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
+                break;
+            case U_UNSUPPORTED_ERROR :
+                exception = env->FindClass("java/lang/UnsupportedOperationException");
+                break;
+            default :
+                exception = env->FindClass("java/lang/RuntimeException");
+        }
+        
+        return (env->ThrowNew(exception, emsg) != 0);
+    }
+    return 0;
+}
+
+static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale, 
+        jstring pattern) {
+
+    // the errorcode returned by unum_open
+    UErrorCode status = U_ZERO_ERROR;
+
+    // prepare the pattern string for the call to unum_open
+    const UChar *pattChars = env->GetStringChars(pattern, NULL);
+    int pattLen = env->GetStringLength(pattern);
+
+    // prepare the locale string for the call to unum_open
+    const char *localeChars = env->GetStringUTFChars(locale, NULL);
+
+    // open a default type number format
+    UNumberFormat *fmt = unum_open(UNUM_PATTERN_DECIMAL, pattChars, pattLen, 
+            localeChars, NULL, &status);
+    
+    // release the allocated strings
+    env->ReleaseStringChars(pattern, pattChars);
+    env->ReleaseStringUTFChars(locale, localeChars);
+
+    // check for an error
+    if ( icuError(env, status) != FALSE) {
+        return 0;
+    }
+
+    // return the handle to the number format
+    return (long) fmt;
+}
+
+static void closeDecimalFormatImpl(JNIEnv *env, jclass clazz, jint addr) {
+
+    // get the pointer to the number format    
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    // close this number format
+    unum_close(fmt);
+}
+
+static void setSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol, 
+        jstring text) {
+    
+    // the errorcode returned by unum_setSymbol
+    UErrorCode status = U_ZERO_ERROR;
+
+    // get the pointer to the number format    
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    // prepare the symbol string for the call to unum_setSymbol
+    const UChar *textChars = env->GetStringChars(text, NULL);
+    int textLen = env->GetStringLength(text);
+
+    // set the symbol
+    unum_setSymbol(fmt, (UNumberFormatSymbol) symbol, textChars, textLen, 
+            &status);
+    
+    // release previously allocated space
+    env->ReleaseStringChars(text, textChars);
+
+    // check if an error occured
+    icuError(env, status);
+}
+
+static jstring getSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol) {
+
+    uint32_t resultlength, reslenneeded;
+
+    // the errorcode returned by unum_setSymbol
+    UErrorCode status = U_ZERO_ERROR;
+
+    // get the pointer to the number format    
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    UChar* result = NULL;
+    resultlength=0;
+
+    // find out how long the result will be
+    reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result, 
+            resultlength, &status);
+
+    result = NULL;
+    if(status==U_BUFFER_OVERFLOW_ERROR) {
+        status=U_ZERO_ERROR;
+        resultlength=reslenneeded+1;
+        result=(UChar*)malloc(sizeof(UChar) * resultlength);
+        reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result, 
+                resultlength, &status);
+    }
+    if (icuError(env, status) != FALSE) {
+        return NULL;
+    }
+
+    jstring res = env->NewString(result, reslenneeded);
+
+    free(result);
+
+    return res;
+}
+    
+static void setAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol, 
+        jint value) {
+    
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    unum_setAttribute(fmt, (UNumberFormatAttribute) symbol, value);
+}
+    
+static jint getAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol) {
+    
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    int res = unum_getAttribute(fmt, (UNumberFormatAttribute) symbol);
+
+    return res;
+}
+
+static void setTextAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol, 
+        jstring text) {
+
+    // the errorcode returned by unum_setSymbol
+    UErrorCode status = U_ZERO_ERROR;
+
+    // get the pointer to the number format    
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    const UChar *textChars = env->GetStringChars(text, NULL);
+    int textLen = env->GetStringLength(text);
+
+    unum_setTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, textChars, 
+            textLen, &status);
+    
+    env->ReleaseStringChars(text, textChars);
+
+    icuError(env, status);
+}
+
+static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr, 
+        jint symbol) {
+
+    uint32_t resultlength, reslenneeded;
+
+    // the errorcode returned by unum_setSymbol
+    UErrorCode status = U_ZERO_ERROR;
+
+    // get the pointer to the number format    
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    UChar* result = NULL;
+    resultlength=0;
+
+    // find out how long the result will be
+    reslenneeded=unum_getTextAttribute(fmt, (UNumberFormatTextAttribute) symbol, 
+            result, resultlength, &status);
+
+    result = NULL;
+    if(status==U_BUFFER_OVERFLOW_ERROR) {
+        status=U_ZERO_ERROR;
+        resultlength=reslenneeded+1;
+        result=(UChar*)malloc(sizeof(UChar) * resultlength);
+        reslenneeded=unum_getTextAttribute(fmt, 
+                (UNumberFormatTextAttribute) symbol, result, resultlength, 
+                &status);
+    }
+    if (icuError(env, status) != FALSE) {
+        return NULL;
+    }
+
+    jstring res = env->NewString(result, reslenneeded);
+
+    free(result);
+
+    return res;
+}
+
+static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr, 
+        jboolean localized, jstring pattern) {
+
+    // the errorcode returned by unum_setSymbol
+    UErrorCode status = U_ZERO_ERROR;
+
+    // get the pointer to the number format    
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    const UChar *pattChars = env->GetStringChars(pattern, NULL);
+    int pattLen = env->GetStringLength(pattern);
+
+    unum_applyPattern(fmt, localized, pattChars, pattLen, NULL, &status);
+
+    env->ReleaseStringChars(pattern, pattChars);
+
+    icuError(env, status);
+}
+
+static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr, 
+        jboolean localized) {
+
+    uint32_t resultlength, reslenneeded;
+
+    // the errorcode returned by unum_setSymbol
+    UErrorCode status = U_ZERO_ERROR;
+
+    // get the pointer to the number format    
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    UChar* result = NULL;
+    resultlength=0;
+
+    // find out how long the result will be
+    reslenneeded=unum_toPattern(fmt, localized, result, resultlength, &status);
+
+    result = NULL;
+    if(status==U_BUFFER_OVERFLOW_ERROR) {
+        status=U_ZERO_ERROR;
+        resultlength=reslenneeded+1;
+        result=(UChar*)malloc(sizeof(UChar) * resultlength);
+        reslenneeded=unum_toPattern(fmt, localized, result, resultlength, 
+                &status);
+    }
+    if (icuError(env, status) != FALSE) {
+        return NULL;
+    }
+
+    jstring res = env->NewString(result, reslenneeded);
+
+    free(result);
+
+    return res;
+}
+    
+static jstring formatLong(JNIEnv *env, jclass clazz, jint addr, jlong value, 
+        jobject field, jstring fieldType, jobject attributes) {
+
+    const char * fieldPositionClassName = "java/text/FieldPosition";
+    const char * stringBufferClassName = "java/lang/StringBuffer";
+    jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
+    jclass stringBufferClass = env->FindClass(stringBufferClassName);
+    jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setBeginIndex", "(I)V");
+    jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setEndIndex", "(I)V");
+    jmethodID appendMethodID = env->GetMethodID(stringBufferClass, 
+            "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+    const char * fieldName = NULL;
+
+    if(fieldType != NULL) {
+        fieldName = env->GetStringUTFChars(fieldType, NULL);
+    }
+
+    uint32_t reslenneeded;
+    int64_t val = value;
+    UChar *result = NULL;
+
+    FieldPosition fp;
+    fp.setField(FieldPosition::DONT_CARE);
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    DecimalFormat::AttrBuffer attrBuffer = NULL;
+    attrBuffer = (DecimalFormat::AttrBuffer) malloc(sizeof(*attrBuffer));
+    attrBuffer->bufferSize = 128;
+    attrBuffer->buffer = (char *) malloc(129 * sizeof(char));
+    attrBuffer->buffer[0] = '\0';
+
+    DecimalFormat *fmt = (DecimalFormat *)(int)addr;
+
+    UnicodeString *res = new UnicodeString();
+
+    fmt->format(val, *res, fp, attrBuffer);
+
+    reslenneeded = res->extract(NULL, 0, status);
+
+    if(status==U_BUFFER_OVERFLOW_ERROR) {
+        status=U_ZERO_ERROR;
+
+        result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));    
+
+        res->extract(result, reslenneeded + 1, status);
+    }
+    if (icuError(env, status) != FALSE) {
+        free(attrBuffer->buffer);
+        free(attrBuffer);
+        free(result);
+        delete(res);
+        return NULL;
+    }
+
+    int attrLength = 0;
+
+    attrLength = (strlen(attrBuffer->buffer) + 1 );
+
+    if(strlen(attrBuffer->buffer) > 0) {
+
+        // check if we want to get all attributes
+        if(attributes != NULL) {
+            jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1);  // cut off the leading ';'
+            env->CallObjectMethod(attributes, appendMethodID, attrString);
+        }
+
+        // check if we want one special attribute returned in the given FieldPos
+        if(fieldName != NULL && field != NULL) {
+            const char *delimiter = ";";
+            int begin;
+            int end;
+            char * resattr;
+            resattr = strtok(attrBuffer->buffer, delimiter);
+
+            while(resattr != NULL && strcmp(resattr, fieldName) != 0) {
+                resattr = strtok(NULL, delimiter);
+            }
+
+            if(resattr != NULL && strcmp(resattr, fieldName) == 0) {
+                resattr = strtok(NULL, delimiter);
+                begin = (int) strtol(resattr, NULL, 10);
+                resattr = strtok(NULL, delimiter);
+                end = (int) strtol(resattr, NULL, 10);
+
+                env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin);
+                env->CallVoidMethod(field, setEndIndexMethodID, (jint) end);
+            }
+        }
+    }
+
+    if(fieldType != NULL) {
+        env->ReleaseStringUTFChars(fieldType, fieldName);
+    }
+
+    jstring resulting = env->NewString(result, reslenneeded);
+
+    free(attrBuffer->buffer);
+    free(attrBuffer);
+    free(result);
+    delete(res);
+
+    return resulting;
+}
+
+static jstring formatDouble(JNIEnv *env, jclass clazz, jint addr, jdouble value, 
+        jobject field, jstring fieldType, jobject attributes) {
+
+    const char * fieldPositionClassName = "java/text/FieldPosition";
+    const char * stringBufferClassName = "java/lang/StringBuffer";
+    jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
+    jclass stringBufferClass = env->FindClass(stringBufferClassName);
+    jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setBeginIndex", "(I)V");
+    jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setEndIndex", "(I)V");
+    jmethodID appendMethodID = env->GetMethodID(stringBufferClass, 
+            "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+    const char * fieldName = NULL;
+
+    if(fieldType != NULL) {
+        fieldName = env->GetStringUTFChars(fieldType, NULL);
+    }
+
+    uint32_t reslenneeded;
+    double val = value;
+    UChar *result = NULL;
+
+    FieldPosition fp;
+    fp.setField(FieldPosition::DONT_CARE);
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    DecimalFormat::AttrBuffer attrBuffer = NULL;
+    attrBuffer = (DecimalFormat::AttrBuffer) malloc(sizeof(*attrBuffer));
+    attrBuffer->bufferSize = 128;
+    attrBuffer->buffer = (char *) malloc(129 * sizeof(char));
+    attrBuffer->buffer[0] = '\0';
+
+    DecimalFormat *fmt = (DecimalFormat *)(int)addr;
+
+    UnicodeString *res = new UnicodeString();
+
+    fmt->format(val, *res, fp, attrBuffer);
+
+    reslenneeded = res->extract(NULL, 0, status);
+
+    if(status==U_BUFFER_OVERFLOW_ERROR) {
+        status=U_ZERO_ERROR;
+
+        result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));    
+
+        res->extract(result, reslenneeded + 1, status);
+
+    }
+    if (icuError(env, status) != FALSE) {
+        free(attrBuffer->buffer);
+        free(attrBuffer);
+        free(result);
+        delete(res);
+        return NULL;
+    }
+
+    int attrLength = 0;
+
+    attrLength = (strlen(attrBuffer->buffer) + 1 );
+
+    if(strlen(attrBuffer->buffer) > 0) {
+
+        // check if we want to get all attributes
+        if(attributes != NULL) {
+            jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1);  // cut off the leading ';'
+            env->CallObjectMethod(attributes, appendMethodID, attrString);
+        }
+
+        // check if we want one special attribute returned in the given FieldPos
+        if(fieldName != NULL && field != NULL) {
+            const char *delimiter = ";";
+            int begin;
+            int end;
+            char * resattr;
+            resattr = strtok(attrBuffer->buffer, delimiter);
+
+            while(resattr != NULL && strcmp(resattr, fieldName) != 0) {
+                resattr = strtok(NULL, delimiter);
+            }
+
+            if(resattr != NULL && strcmp(resattr, fieldName) == 0) {
+                resattr = strtok(NULL, delimiter);
+                begin = (int) strtol(resattr, NULL, 10);
+                resattr = strtok(NULL, delimiter);
+                end = (int) strtol(resattr, NULL, 10);
+
+                env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin);
+                env->CallVoidMethod(field, setEndIndexMethodID, (jint) end);
+            }
+        }
+    }
+
+    if(fieldType != NULL) {
+        env->ReleaseStringUTFChars(fieldType, fieldName);
+    }
+
+    jstring resulting = env->NewString(result, reslenneeded);
+
+    free(attrBuffer->buffer);
+    free(attrBuffer);
+    free(result);
+    delete(res);
+
+    return resulting;
+}
+    
+static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring value, 
+        jobject field, jstring fieldType, jobject attributes, jint scale) {
+
+    //const char * valueUTF = env->GetStringUTFChars(value, NULL);
+    //LOGI("ENTER formatDigitList: %s", valueUTF);
+    //env->ReleaseStringUTFChars(value, valueUTF);
+
+    // prepare the classes and method ids
+    const char * fieldPositionClassName = "java/text/FieldPosition";
+    const char * stringBufferClassName = "java/lang/StringBuffer";
+    jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
+    jclass stringBufferClass = env->FindClass(stringBufferClassName);
+    jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setBeginIndex", "(I)V");
+    jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setEndIndex", "(I)V");
+    jmethodID appendMethodID = env->GetMethodID(stringBufferClass, 
+            "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+
+    const char * fieldName = NULL;
+    if(fieldType != NULL) {
+        fieldName = env->GetStringUTFChars(fieldType, NULL);
+    }
+
+    uint32_t reslenneeded;
+
+    jboolean isInteger = (scale == 0);
+
+    // prepare digit list
+
+    const char *digits = env->GetStringUTFChars(value, NULL);
+    // length must be string lengt + 2 because there's an additional
+    // character in front of the string ("+" or "-") and a \0 at the end
+    DigitList *digitList = new DigitList(strlen(digits) + 2);
+    digitList->fCount = strlen(digits);
+    strcpy(digitList->fDigits, digits);
+    env->ReleaseStringUTFChars(value, digits);
+
+    digitList->fDecimalAt = digitList->fCount - scale;
+    digitList->fIsPositive = (*digits != '-');
+    digitList->fRoundingMode = DecimalFormat::kRoundHalfUp;
+
+    UChar *result = NULL;
+
+    FieldPosition fp;
+    fp.setField(FieldPosition::DONT_CARE);
+    fp.setBeginIndex(0);
+    fp.setEndIndex(0);
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    DecimalFormat::AttributeBuffer *attrBuffer = NULL;
+    attrBuffer = (DecimalFormat::AttributeBuffer *) malloc(sizeof(DecimalFormat::AttributeBuffer));
+    attrBuffer->bufferSize = 128;
+    attrBuffer->buffer = (char *) malloc(129 * sizeof(char));
+    attrBuffer->buffer[0] = '\0';
+
+    DecimalFormat *fmt = (DecimalFormat *)(int)addr;
+
+    UnicodeString *res = new UnicodeString();
+
+    fmt->subformat(*res, fp, attrBuffer, *digitList, isInteger);
+    delete digitList;
+
+    reslenneeded = res->extract(NULL, 0, status);
+
+    if(status==U_BUFFER_OVERFLOW_ERROR) {
+        status=U_ZERO_ERROR;
+
+        result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));    
+
+        res->extract(result, reslenneeded + 1, status);
+
+        if (icuError(env, status) != FALSE) {
+            free(result);
+            free(attrBuffer->buffer);
+            free(attrBuffer);
+            delete(res);
+            return NULL;
+        }
+
+    } else {
+        free(attrBuffer->buffer);
+        free(attrBuffer);
+        delete(res);
+        return NULL;        
+    }
+
+    int attrLength = (strlen(attrBuffer->buffer) + 1 );
+
+    if(attrLength > 1) {
+
+        // check if we want to get all attributes
+        if(attributes != NULL) {
+            jstring attrString = env->NewStringUTF(attrBuffer->buffer + 1);  // cut off the leading ';'
+            env->CallObjectMethod(attributes, appendMethodID, attrString);
+        }
+
+        // check if we want one special attribute returned in the given FieldPos
+        if(fieldName != NULL && field != NULL) {
+            const char *delimiter = ";";
+            int begin;
+            int end;
+            char * resattr;
+            resattr = strtok(attrBuffer->buffer, delimiter);
+
+            while(resattr != NULL && strcmp(resattr, fieldName) != 0) {
+                resattr = strtok(NULL, delimiter);
+            }
+
+            if(resattr != NULL && strcmp(resattr, fieldName) == 0) {
+                resattr = strtok(NULL, delimiter);
+                begin = (int) strtol(resattr, NULL, 10);
+                resattr = strtok(NULL, delimiter);
+                end = (int) strtol(resattr, NULL, 10);
+
+                env->CallVoidMethod(field, setBeginIndexMethodID, (jint) begin);
+                env->CallVoidMethod(field, setEndIndexMethodID, (jint) end);
+            }
+        }
+    }
+
+    if(fieldType != NULL) {
+        env->ReleaseStringUTFChars(fieldType, fieldName);
+    }
+
+    jstring resulting = env->NewString(result, reslenneeded);
+
+    free(attrBuffer->buffer);
+    free(attrBuffer);
+    free(result);
+    delete(res);
+
+    //const char * resultUTF = env->GetStringUTFChars(resulting, NULL);
+    //LOGI("RETURN formatDigitList: %s", resultUTF);
+    //env->ReleaseStringUTFChars(resulting, resultUTF);
+
+    return resulting;
+}
+
+static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text, 
+        jobject position) {
+
+    const char * textUTF = env->GetStringUTFChars(text, NULL);
+    env->ReleaseStringUTFChars(text, textUTF);
+
+    const char * parsePositionClassName = "java/text/ParsePosition";
+    const char * longClassName = "java/lang/Long";
+    const char * doubleClassName = "java/lang/Double";
+    const char * bigDecimalClassName = "java/math/BigDecimal";
+    const char * bigIntegerClassName = "java/math/BigInteger";
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    jchar *str = (UChar *)env->GetStringChars(text, NULL);
+    int strlength = env->GetStringLength(text);
+
+    jclass parsePositionClass = env->FindClass(parsePositionClassName);
+    jclass longClass =  env->FindClass(longClassName);
+    jclass doubleClass =  env->FindClass(doubleClassName);
+    jclass bigDecimalClass = env->FindClass(bigDecimalClassName);
+    jclass bigIntegerClass = env->FindClass(bigIntegerClassName);
+
+    jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass, 
+            "getIndex", "()I");
+    jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass, 
+            "setIndex", "(I)V");
+    jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass, 
+            "setErrorIndex", "(I)V");
+
+    jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V");
+    jmethodID dblInitMethodID = env->GetMethodID(doubleClass, "<init>", "(D)V");
+    jmethodID bigDecimalInitMethodID = env->GetMethodID(bigDecimalClass, "<init>", "(Ljava/math/BigInteger;I)V");
+    jmethodID bigIntegerInitMethodID = env->GetMethodID(bigIntegerClass, "<init>", "(Ljava/lang/String;)V");
+    jmethodID doubleValueMethodID = env->GetMethodID(bigDecimalClass, "doubleValue", "()D");
+
+    bool resultAssigned;
+    int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL);
+
+    // make sure the ParsePosition is valid. Actually icu4c would parse a number 
+    // correctly even if the parsePosition is set to -1, but since the RI fails 
+    // for that case we have to fail too
+    if(parsePos < 0 || parsePos > strlength) {
+        return NULL;
+    }
+
+    Formattable res;
+
+    const UnicodeString src((UChar*)str, strlength, strlength);
+    ParsePosition pp;
+    
+    pp.setIndex(parsePos);
+    
+    DigitList digits;
+
+    ((const DecimalFormat*)fmt)->parse(src, resultAssigned, res, pp, FALSE, digits);
+
+    env->ReleaseStringChars(text, str);
+
+    if(pp.getErrorIndex() == -1) {
+        parsePos = pp.getIndex();
+    } else {
+        env->CallVoidMethod(position, setErrorIndexMethodID, 
+                (jint) pp.getErrorIndex());        
+        return NULL;
+    }
+
+    Formattable::Type numType;
+    numType = res.getType();
+    UErrorCode fmtStatus;
+
+    double resultDouble;
+    long resultLong;
+    int64_t resultInt64;
+    UnicodeString resultString;
+    jstring resultStr;
+    int resLength;
+    const char * resultUTF;
+    jobject resultObject1, resultObject2;
+    jdouble doubleTest;
+    jchar * result;
+
+    if (resultAssigned)
+    {
+        switch(numType) {
+        case Formattable::kDouble:
+            resultDouble = res.getDouble();
+            env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+            return env->NewObject(doubleClass, dblInitMethodID, 
+                    (jdouble) resultDouble);
+        case Formattable::kLong:
+            resultLong = res.getLong();
+            env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+            return env->NewObject(longClass, longInitMethodID, 
+                    (jlong) resultLong);
+        case Formattable::kInt64:
+            resultInt64 = res.getInt64();
+            env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+            return env->NewObject(longClass, longInitMethodID, 
+                    (jlong) resultInt64);
+        default:
+            break;
+        }
+    }
+    else
+    {
+        int scale = digits.fCount - digits.fDecimalAt;
+        digits.fDigits[digits.fCount] = 0;  // mc: ATTENTION: Abuse of Implementation Knowlegde!
+        if (digits.fIsPositive) {
+            resultStr = env->NewStringUTF(digits.fDigits);
+        } else {
+            if (digits.fCount == 0) {
+                env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+                return env->NewObject(doubleClass, dblInitMethodID, (jdouble)-0);
+            } else {
+                *(digits.fDigits - 1) = '-';  // mc: ATTENTION: Abuse of Implementation Knowlegde!
+                resultStr = env->NewStringUTF(digits.fDigits - 1);
+            }
+        }
+
+        env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+
+        resultObject1 = env->NewObject(bigIntegerClass, bigIntegerInitMethodID, resultStr);
+        resultObject2 = env->NewObject(bigDecimalClass, bigDecimalInitMethodID, resultObject1, scale);
+        return resultObject2;
+    }
+    return NULL;    // Don't see WHY, however!!! (Control never reaches here!!!)
+}
+
+static jint cloneImpl(JNIEnv *env, jclass clazz, jint addr) {
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    UNumberFormat *result = unum_clone(fmt, &status);
+
+    if(icuError(env, status) != FALSE) {
+        return 0;
+    }
+
+    return (long) result;
+
+}
+
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    {"openDecimalFormatImpl", "(Ljava/lang/String;Ljava/lang/String;)I", 
+            (void*) openDecimalFormatImpl},
+    {"closeDecimalFormatImpl", "(I)V", (void*) closeDecimalFormatImpl},
+    {"setSymbol", "(IILjava/lang/String;)V", (void*) setSymbol},
+    {"getSymbol", "(II)Ljava/lang/String;", (void*) getSymbol},
+    {"setAttribute", "(III)V", (void*) setAttribute},
+    {"getAttribute", "(II)I", (void*) getAttribute},
+    {"setTextAttribute", "(IILjava/lang/String;)V", (void*) setTextAttribute},
+    {"getTextAttribute", "(II)Ljava/lang/String;", (void*) getTextAttribute},
+    {"applyPatternImpl", "(IZLjava/lang/String;)V", (void*) applyPatternImpl},
+    {"toPatternImpl", "(IZ)Ljava/lang/String;", (void*) toPatternImpl},
+    {"format", 
+            "(IJLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", 
+            (void*) formatLong},
+    {"format", 
+            "(IDLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", 
+            (void*) formatDouble},
+    {"format", 
+            "(ILjava/lang/String;Ljava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;I)Ljava/lang/String;", 
+            (void*) formatDigitList},
+    {"parse", 
+            "(ILjava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Number;", 
+            (void*) parse},
+    {"cloneImpl", "(I)I", (void*) cloneImpl}
+};
+int register_com_ibm_icu4jni_text_NativeDecimalFormat(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, 
+            "com/ibm/icu4jni/text/NativeDecimalFormat", gMethods, 
+            NELEM(gMethods));
+}
diff --git a/libcore/icu/src/main/native/ErrorCode.c b/libcore/icu/src/main/native/ErrorCode.c
new file mode 100644
index 0000000..b3e43cd
--- /dev/null
+++ b/libcore/icu/src/main/native/ErrorCode.c
@@ -0,0 +1,57 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*
+*******************************************************************************
+*/
+
+#include "ErrorCode.h"
+
+/* private data members ----------------------------------------------------*/
+
+/**
+* Name of the java runtime exception classes
+*/
+#define ILLEGALARGUMENTEXCEPTION_       "java/lang/IllegalArgumentException"
+#define ARRAYINDEXOUTOFBOUNDSEXCEPTION_ "java/lang/ArrayIndexOutOfBoundsException"
+#define UNSUPPORTEDOPERATIONEXCEPTION_  "java/lang/UnsupportedOperationException"
+#define RUNTIMEEXCEPTION_               "java/lang/RuntimeException"
+
+/* public methods ---------------------------------------------------------*/
+
+/**
+* Checks if an error has occured. 
+* Throws a generic Java RuntimeException if an error has occured.
+* @param env JNI environment variable
+* @param errorcode code to determine if it is an erro
+* @return 0 if errorcode is not an error, 1 if errorcode is an error, but the 
+*         creation of the exception to be thrown fails
+* @exception thrown if errorcode represents an error
+*/
+UBool icu4jni_error(JNIEnv *env, UErrorCode errorcode)
+{
+  const char   *emsg      = u_errorName(errorcode);
+        jclass  exception;
+
+  if (errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
+    switch (errorcode) {
+      case U_ILLEGAL_ARGUMENT_ERROR :
+        exception = (*env)->FindClass(env, ILLEGALARGUMENTEXCEPTION_);
+        break;
+      case U_INDEX_OUTOFBOUNDS_ERROR :
+      case U_BUFFER_OVERFLOW_ERROR :
+        exception = (*env)->FindClass(env, ARRAYINDEXOUTOFBOUNDSEXCEPTION_);
+        break;
+      case U_UNSUPPORTED_ERROR :
+        exception = (*env)->FindClass(env, UNSUPPORTEDOPERATIONEXCEPTION_);
+        break;
+      default :
+        exception = (*env)->FindClass(env, RUNTIMEEXCEPTION_);
+    }
+
+    return ((*env)->ThrowNew(env, exception, emsg) != 0);
+  }
+  return 0;
+}
diff --git a/libcore/icu/src/main/native/ErrorCode.h b/libcore/icu/src/main/native/ErrorCode.h
new file mode 100644
index 0000000..a5bbfc6
--- /dev/null
+++ b/libcore/icu/src/main/native/ErrorCode.h
@@ -0,0 +1,27 @@
+/**
+*******************************************************************************
+* Copyright (C) 1996-2005, International Business Machines Corporation and    *
+* others. All Rights Reserved.                                                *
+*******************************************************************************
+*******************************************************************************
+*/
+
+#ifndef ERRORCODE_H
+#define ERRORCODE_H
+
+#include <jni.h>
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+
+/**
+* Checks if an error has occured. 
+* Throws a generic Java RuntimeException if an error has occured.
+* @param env JNI environment variable
+* @param errorcode code to determine if it is an erro
+* @return 0 if errorcode is not an error, 1 if errorcode is an error, but the 
+*         creation of the exception to be thrown fails
+* @exception thrown if errorcode represents an error
+*/
+UBool icu4jni_error(JNIEnv *env, UErrorCode errorcode);
+
+#endif
diff --git a/libcore/icu/src/main/native/RBNFInterface.cpp b/libcore/icu/src/main/native/RBNFInterface.cpp
new file mode 100644
index 0000000..17e7155
--- /dev/null
+++ b/libcore/icu/src/main/native/RBNFInterface.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.
+ */
+ 
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/numfmt.h"
+#include "unicode/rbnf.h"
+#include "unicode/fmtable.h"
+#include "unicode/ustring.h"
+#include "unicode/locid.h"
+#include "ErrorCode.h"
+#include <stdlib.h>
+#include <string.h>
+
+static UBool icuError(JNIEnv *env, UErrorCode errorcode)
+{
+  const char  *emsg = u_errorName(errorcode);
+  jclass  exception;
+
+  if (errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
+    switch (errorcode) {
+      case U_ILLEGAL_ARGUMENT_ERROR :
+        exception = env->FindClass("java/lang/IllegalArgumentException");
+        break;
+      case U_INDEX_OUTOFBOUNDS_ERROR :
+      case U_BUFFER_OVERFLOW_ERROR :
+        exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
+        break;
+      case U_UNSUPPORTED_ERROR :
+        exception = env->FindClass("java/lang/UnsupportedOperationException");
+        break;
+      default :
+        exception = env->FindClass("java/lang/RuntimeException");
+    }
+
+    return (env->ThrowNew(exception, emsg) != 0);
+  }
+  return 0;
+}
+
+static jint openRBNFImpl1(JNIEnv* env, jclass clazz, 
+        jint type, jstring locale) {
+
+    // LOGI("ENTER openRBNFImpl1");
+
+    // the errorcode returned by unum_open
+    UErrorCode status = U_ZERO_ERROR;
+
+    // prepare the locale string for the call to unum_open
+    const char *localeChars = env->GetStringUTFChars(locale, NULL);
+
+    URBNFRuleSetTag style;
+    if(type == 0) {
+        style = URBNF_SPELLOUT;
+    } else if(type == 1) {
+        style = URBNF_ORDINAL;
+    } else if(type == 2) {
+        style = URBNF_DURATION;
+    } else if(type == 3) {
+        style = URBNF_COUNT;
+    } else {
+        printf("error");
+    }
+    
+    Locale loc = Locale::createFromName(localeChars);
+
+    // open a default type number format
+    RuleBasedNumberFormat *fmt = new RuleBasedNumberFormat(style, loc, status);
+
+    // release the allocated strings
+    env->ReleaseStringUTFChars(locale, localeChars);
+
+    // check for an error
+    if ( icuError(env, status) != FALSE) {
+        return 0;
+    }
+
+    // return the handle to the number format
+    return (long) fmt;
+
+}
+
+static jint openRBNFImpl2(JNIEnv* env, jclass clazz, 
+        jstring rule, jstring locale) {
+
+    // LOGI("ENTER openRBNFImpl2");
+
+    // the errorcode returned by unum_open
+    UErrorCode status = U_ZERO_ERROR;
+
+    // prepare the pattern string for the call to unum_open
+    const UChar *ruleChars = env->GetStringChars(rule, NULL);
+    int ruleLen = env->GetStringLength(rule);
+
+    // prepare the locale string for the call to unum_open
+    const char *localeChars = env->GetStringUTFChars(locale, NULL);
+
+    // open a rule based number format
+    UNumberFormat *fmt = unum_open(UNUM_PATTERN_RULEBASED, ruleChars, ruleLen, 
+                localeChars, NULL, &status);
+
+    // release the allocated strings
+    env->ReleaseStringChars(rule, ruleChars);
+    env->ReleaseStringUTFChars(locale, localeChars);
+
+    // check for an error
+    if ( icuError(env, status) != FALSE) {
+        return 0;
+    }
+
+    // return the handle to the number format
+    return (long) fmt;
+
+}
+
+static void closeRBNFImpl(JNIEnv *env, jclass clazz, jint addr) {
+
+    // LOGI("ENTER closeRBNFImpl");
+
+    // get the pointer to the number format    
+    RuleBasedNumberFormat *fmt = (RuleBasedNumberFormat *)(int)addr;
+
+    // close this number format
+    delete fmt;
+}
+
+static jstring formatLongRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jlong value, 
+        jobject field, jstring fieldType, jobject attributes) {
+
+    // LOGI("ENTER formatLongRBNFImpl");
+
+    const char * fieldPositionClassName = "java/text/FieldPosition";
+    const char * stringBufferClassName = "java/lang/StringBuffer";
+    jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
+    jclass stringBufferClass = env->FindClass(stringBufferClassName);
+    jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setBeginIndex", "(I)V");
+    jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setEndIndex", "(I)V");
+    jmethodID appendMethodID = env->GetMethodID(stringBufferClass, 
+            "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+    const char * fieldName = NULL;
+
+    if(fieldType != NULL) {
+        fieldName = env->GetStringUTFChars(fieldType, NULL);
+    }
+
+    uint32_t reslenneeded;
+    int64_t val = value;
+    UChar *result = NULL;
+
+    FieldPosition fp;
+    fp.setField(FieldPosition::DONT_CARE);
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    RuleBasedNumberFormat *fmt = (RuleBasedNumberFormat *)(int)addr;
+
+    UnicodeString res;
+
+    fmt->format(val, res, fp);
+
+    reslenneeded = res.extract(NULL, 0, status);
+
+    if(status==U_BUFFER_OVERFLOW_ERROR) {
+        status=U_ZERO_ERROR;
+
+        result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));    
+
+        res.extract(result, reslenneeded + 1, status);
+    }
+    if (icuError(env, status) != FALSE) {
+        free(result);
+        return NULL;
+    }
+
+    if(fieldType != NULL) {
+        env->ReleaseStringUTFChars(fieldType, fieldName);
+    }
+
+    jstring resulting = env->NewString(result, reslenneeded);
+
+    free(result);
+
+    return resulting;
+}
+
+static jstring formatDoubleRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jdouble value, 
+        jobject field, jstring fieldType, jobject attributes) {
+
+    // LOGI("ENTER formatDoubleRBNFImpl");
+
+    const char * fieldPositionClassName = "java/text/FieldPosition";
+    const char * stringBufferClassName = "java/lang/StringBuffer";
+    jclass fieldPositionClass = env->FindClass(fieldPositionClassName);
+    jclass stringBufferClass = env->FindClass(stringBufferClassName);
+    jmethodID setBeginIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setBeginIndex", "(I)V");
+    jmethodID setEndIndexMethodID = env->GetMethodID(fieldPositionClass, 
+            "setEndIndex", "(I)V");
+    jmethodID appendMethodID = env->GetMethodID(stringBufferClass, 
+            "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
+
+    const char * fieldName = NULL;
+
+    if(fieldType != NULL) {
+        fieldName = env->GetStringUTFChars(fieldType, NULL);
+    }
+
+    uint32_t reslenneeded;
+    double val = value;
+    UChar *result = NULL;
+
+    FieldPosition fp;
+    fp.setField(FieldPosition::DONT_CARE);
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    RuleBasedNumberFormat *fmt = (RuleBasedNumberFormat *)(int)addr;
+
+    UnicodeString res;
+
+    fmt->format(val, res, fp);
+
+    reslenneeded = res.extract(NULL, 0, status);
+
+    if(status==U_BUFFER_OVERFLOW_ERROR) {
+        status=U_ZERO_ERROR;
+
+        result = (UChar*)malloc(sizeof(UChar) * (reslenneeded + 1));    
+
+        res.extract(result, reslenneeded + 1, status);
+    }
+    if (icuError(env, status) != FALSE) {
+        free(result);
+        return NULL;
+    }
+
+    if(fieldType != NULL) {
+        env->ReleaseStringUTFChars(fieldType, fieldName);
+    }
+
+    jstring resulting = env->NewString(result, reslenneeded);
+
+    free(result);
+
+    return resulting;
+}
+
+static jobject parseRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jstring text, 
+        jobject position, jboolean lenient) {
+
+    // LOGI("ENTER parseRBNFImpl");
+
+    const char * parsePositionClassName = "java/text/ParsePosition";
+    const char * longClassName = "java/lang/Long";
+    const char * doubleClassName = "java/lang/Double";
+
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+
+    jchar *str = (UChar *)env->GetStringChars(text, NULL);
+    int strlength = env->GetStringLength(text);
+
+    jclass parsePositionClass = env->FindClass(parsePositionClassName);
+    jclass longClass =  env->FindClass(longClassName);
+    jclass doubleClass =  env->FindClass(doubleClassName);
+
+    jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass, 
+            "getIndex", "()I");
+    jmethodID setIndexMethodID = env->GetMethodID(parsePositionClass, 
+            "setIndex", "(I)V");
+    jmethodID setErrorIndexMethodID = env->GetMethodID(parsePositionClass, 
+            "setErrorIndex", "(I)V");
+
+    jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V");
+    jmethodID dblInitMethodID = env->GetMethodID(doubleClass, "<init>", "(D)V");
+
+    int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL);
+
+    // make sure the ParsePosition is valid. Actually icu4c would parse a number 
+    // correctly even if the parsePosition is set to -1, but since the RI fails 
+    // for that case we have to fail too
+    if(parsePos < 0 || parsePos > strlength) {
+        return NULL;
+    }
+
+    Formattable res;
+
+    const UnicodeString src((UChar*)str, strlength, strlength);
+    ParsePosition pp;
+    
+    pp.setIndex(parsePos);
+    
+    if(lenient) {
+        unum_setAttribute(fmt, UNUM_LENIENT_PARSE, JNI_TRUE);
+    }
+    
+    ((const NumberFormat*)fmt)->parse(src, res, pp);
+
+    if(lenient) {
+        unum_setAttribute(fmt, UNUM_LENIENT_PARSE, JNI_FALSE);
+    }
+    
+    env->ReleaseStringChars(text, str);
+
+    if(pp.getErrorIndex() == -1) {
+        parsePos = pp.getIndex();
+    } else {
+        env->CallVoidMethod(position, setErrorIndexMethodID, 
+                (jint) pp.getErrorIndex());        
+        return NULL;
+    }
+
+    Formattable::Type numType;
+    numType = res.getType();
+    UErrorCode fmtStatus;
+
+    double resultDouble;
+    long resultLong;
+    int64_t resultInt64;
+
+    switch(numType) {
+        case Formattable::kDouble:
+            resultDouble = res.getDouble();
+            env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+            return env->NewObject(doubleClass, dblInitMethodID, 
+                    (jdouble) resultDouble);
+        case Formattable::kLong:
+            resultLong = res.getLong();
+            env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+            return env->NewObject(longClass, longInitMethodID, 
+                    (jlong) resultLong);
+        case Formattable::kInt64:
+            resultInt64 = res.getInt64();
+            env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+            return env->NewObject(longClass, longInitMethodID, 
+                    (jlong) resultInt64);
+        default:
+            break;
+    }
+
+    return NULL;
+}
+
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    {"openRBNFImpl", "(ILjava/lang/String;)I", (void*) openRBNFImpl1},
+    {"openRBNFImpl", "(Ljava/lang/String;Ljava/lang/String;)I", 
+            (void*) openRBNFImpl2},
+    {"closeRBNFImpl", "(I)V", (void*) closeRBNFImpl},
+    {"formatRBNFImpl", 
+            "(IJLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", 
+            (void*) formatLongRBNFImpl},
+    {"formatRBNFImpl",
+            "(IDLjava/text/FieldPosition;Ljava/lang/String;Ljava/lang/StringBuffer;)Ljava/lang/String;", 
+            (void*) formatDoubleRBNFImpl},
+    {"parseRBNFImpl", 
+            "(ILjava/lang/String;Ljava/text/ParsePosition;Z)Ljava/lang/Number;", 
+            (void*) parseRBNFImpl},
+};
+int register_com_ibm_icu4jni_text_NativeRBNF(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, 
+            "com/ibm/icu4jni/text/RuleBasedNumberFormat", gMethods, 
+            NELEM(gMethods));
+}
diff --git a/libcore/icu/src/main/native/RegExInterface.cpp b/libcore/icu/src/main/native/RegExInterface.cpp
new file mode 100644
index 0000000..f607d59
--- /dev/null
+++ b/libcore/icu/src/main/native/RegExInterface.cpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include "unicode/uregex.h"
+#include "unicode/utypes.h"
+#include "unicode/parseerr.h"
+
+#include <jni.h>
+#include <JNIHelp.h>
+//#include <android_runtime/AndroidRuntime.h>
+
+static const jchar EMPTY_STRING = 0;
+ 
+static void throwPatternSyntaxException(JNIEnv* env, UErrorCode status, jstring pattern, UParseError error)
+{
+    jclass clazz = env->FindClass("java/util/regex/PatternSyntaxException");
+    jmethodID method = env->GetMethodID(clazz, "<init>", "(Ljava/lang/String;Ljava/lang/String;I)V");
+    
+    jstring message = env->NewStringUTF(u_errorName(status));
+    jthrowable except = (jthrowable)(env->NewObject(clazz, method, message, pattern, error.offset));
+    env->Throw(except);
+}
+
+static void throwRuntimeException(JNIEnv* env, UErrorCode status)
+{
+    jniThrowException(env, "java/lang/RuntimeException", u_errorName(status));
+}
+
+static URegularExpression* open(JNIEnv* env, jclass clazz, jstring pattern, jint flags)
+{
+    flags = flags | UREGEX_ERROR_ON_UNKNOWN_ESCAPES;
+    
+    jchar const * patternRaw;
+    int patternLen = env->GetStringLength(pattern);
+    if (patternLen == 0) {
+        patternRaw = &EMPTY_STRING;
+        patternLen = -1;
+    } else {
+        patternRaw = env->GetStringChars(pattern, NULL);
+    }
+
+    UErrorCode status = U_ZERO_ERROR;
+    UParseError error;
+    error.offset = -1;
+    
+    URegularExpression* result = uregex_open(patternRaw, patternLen, flags, &error, &status);
+    if (patternLen != -1) {
+        env->ReleaseStringChars(pattern, patternRaw);
+    }    
+    if (!U_SUCCESS(status)) {
+        throwPatternSyntaxException(env, status, pattern, error);
+    }
+    
+    return result;
+}
+
+static URegularExpression* _clone(JNIEnv* env, jclass clazz, jint regex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+
+    URegularExpression* result = uregex_clone((URegularExpression*)regex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+
+    return result;
+}
+
+static void _close(JNIEnv* env, jclass clazz, URegularExpression* regex)
+{
+    uregex_close(regex);
+}
+
+static void setText(JNIEnv* env, jclass clazz, URegularExpression* regex, jstring text)
+{
+    jchar const * textRaw;
+    int textLen = env->GetStringLength(text);
+    if (textLen == 0) {
+        textLen = -1;
+        textRaw = &EMPTY_STRING;
+    } else {
+        textRaw = env->GetStringChars(text, NULL);
+    }
+    
+    UErrorCode status = U_ZERO_ERROR;
+    
+    uregex_setText(regex, textRaw, textLen, &status);
+    if (textLen != -1) {
+        env->ReleaseStringChars(text, textRaw);
+    }    
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+}
+
+static jboolean matches(JNIEnv* env, jclass clazz, URegularExpression* regex, jint startIndex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    
+    jboolean result = uregex_matches(regex, startIndex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+    
+    return result;
+}
+
+static jboolean lookingAt(JNIEnv* env, jclass clazz, URegularExpression* regex, jint startIndex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    
+    jboolean result = uregex_lookingAt(regex, startIndex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+    
+    return result;
+}
+
+static jboolean find(JNIEnv* env, jclass clazz, URegularExpression* regex, jint startIndex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    
+    jboolean result = uregex_find(regex, startIndex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+
+    return result;
+}
+
+static jboolean findNext(JNIEnv* env, jclass clazz, URegularExpression* regex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+
+    jboolean result = uregex_findNext(regex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+    
+    return result;
+}
+
+static jint groupCount(JNIEnv* env, jclass clazz, URegularExpression* regex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+
+    jint result = uregex_groupCount(regex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+
+    return result;
+}
+
+static void startEnd(JNIEnv* env, jclass clazz, URegularExpression* regex, jintArray offsets)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    
+    jint * offsetsRaw = env->GetIntArrayElements(offsets, NULL);
+
+    int groupCount = uregex_groupCount(regex, &status);
+    for (int i = 0; i <= groupCount && U_SUCCESS(status); i++) {
+        offsetsRaw[2 * i + 0] = uregex_start(regex, i, &status);
+        offsetsRaw[2 * i + 1] = uregex_end(regex, i, &status);
+    }
+    
+    env->ReleaseIntArrayElements(offsets, offsetsRaw, 0);
+    
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+}
+
+static void setRegion(JNIEnv* env, jclass clazz, URegularExpression* regex, jint start, jint end)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    uregex_setRegion(regex, start, end, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+}
+
+static jint regionStart(JNIEnv* env, jclass clazz, URegularExpression* regex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    int result = uregex_regionStart(regex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+    return result;
+}
+
+static jint regionEnd(JNIEnv* env, jclass clazz, URegularExpression* regex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    int result = uregex_regionEnd(regex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+    return result;
+}
+
+static void useTransparentBounds(JNIEnv* env, jclass clazz, URegularExpression* regex, jboolean value)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    uregex_useTransparentBounds(regex, value, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+}
+
+static jboolean hasTransparentBounds(JNIEnv* env, jclass clazz, URegularExpression* regex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    jboolean result = uregex_hasTransparentBounds(regex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+    return result;
+}
+
+static void useAnchoringBounds(JNIEnv* env, jclass clazz, URegularExpression* regex, jboolean value)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    uregex_useAnchoringBounds(regex, value, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+}
+
+static jboolean hasAnchoringBounds(JNIEnv* env, jclass clazz, URegularExpression* regex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    jboolean result = uregex_hasAnchoringBounds(regex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+    return result;
+}
+
+static jboolean hitEnd(JNIEnv* env, jclass clazz, URegularExpression* regex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    jboolean result = uregex_hitEnd(regex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+    return result;
+}
+
+static jboolean requireEnd(JNIEnv* env, jclass clazz, URegularExpression* regex)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    jboolean result = uregex_requireEnd(regex, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+    return result;
+}
+
+static void reset(JNIEnv* env, jclass clazz, URegularExpression* regex, jint position)
+{
+    UErrorCode status = U_ZERO_ERROR;
+    uregex_reset(regex, position, &status);
+    if (!U_SUCCESS(status)) {
+        throwRuntimeException(env, status);
+    }
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod sMethods[] = {
+    /* name, signature, funcPtr */
+    { "open",                 "(Ljava/lang/String;I)I", (void*)open       },
+    { "clone",                "(I)I",                   (void*)_clone     },
+    { "close",                "(I)V",                   (void*)_close     },
+    { "setText",              "(ILjava/lang/String;)V", (void*)setText    },
+    { "matches",              "(II)Z",                  (void*)matches    },
+    { "lookingAt",            "(II)Z",                  (void*)lookingAt  },
+    { "find",                 "(II)Z",                  (void*)find       },
+    { "findNext",             "(I)Z",                   (void*)findNext   },
+    { "groupCount",           "(I)I",                   (void*)groupCount },
+    { "startEnd",             "(I[I)V",                 (void*)startEnd   },
+    { "setRegion",            "(III)V",                 (void*)setRegion  },
+    { "regionStart",          "(I)I",                   (void*)regionStart },
+    { "regionEnd",            "(I)I",                   (void*)regionEnd  },
+    { "useTransparentBounds", "(IZ)V",                  (void*)useTransparentBounds },
+    { "hasTransparentBounds", "(I)Z",                   (void*)hasTransparentBounds },
+    { "useAnchoringBounds",   "(IZ)V",                  (void*)useAnchoringBounds },
+    { "hasAnchoringBounds",   "(I)Z",                   (void*)hasAnchoringBounds },
+    { "hitEnd",               "(I)Z",                   (void*)hitEnd },
+    { "requireEnd",           "(I)Z",                   (void*)requireEnd },
+    { "reset",                "(II)V",                  (void*)reset }
+};
+
+extern "C" int register_com_ibm_icu4jni_regex_NativeRegEx(JNIEnv* env)
+{
+    jclass clazz;
+
+    clazz = env->FindClass("com/ibm/icu4jni/regex/NativeRegEx");
+    if (clazz == NULL) {
+        return -1;
+    }
+
+    if (env->RegisterNatives(clazz, sMethods, NELEM(sMethods)) < 0) {
+        return -1;
+    }
+    
+    return 0;
+}
diff --git a/libcore/icu/src/main/native/ResourceInterface.cpp b/libcore/icu/src/main/native/ResourceInterface.cpp
new file mode 100644
index 0000000..a0c6922
--- /dev/null
+++ b/libcore/icu/src/main/native/ResourceInterface.cpp
@@ -0,0 +1,1417 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "JNIHelp.h"
+#include "AndroidSystemNatives.h"
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+#include "unicode/ucal.h"
+#include "unicode/gregocal.h"
+#include "unicode/ucurr.h"
+#include "unicode/calendar.h"
+#include "unicode/datefmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/uclean.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/strenum.h"
+#include "unicode/ustring.h"
+#include "unicode/timezone.h"
+#include "ErrorCode.h"
+#include <cutils/log.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+
+jclass string_class;
+
+static UBool icuError(JNIEnv *env, UErrorCode errorcode)
+{
+  const char   *emsg      = u_errorName(errorcode);
+        jclass  exception;
+
+  if (U_FAILURE(errorcode)) {
+    switch (errorcode) {
+      case U_ILLEGAL_ARGUMENT_ERROR :
+        exception = env->FindClass("java/lang/IllegalArgumentException");
+        break;
+      case U_INDEX_OUTOFBOUNDS_ERROR :
+      case U_BUFFER_OVERFLOW_ERROR :
+        exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
+        break;
+      case U_UNSUPPORTED_ERROR :
+        exception = env->FindClass("java/lang/UnsupportedOperationException");
+        break;
+      default :
+        exception = env->FindClass("java/lang/RuntimeException");
+    }
+
+    return (env->ThrowNew(exception, emsg) != 0);
+  }
+  return 0;
+}
+
+static Locale getLocale(JNIEnv *env, jstring locale) {
+    const char *name = env->GetStringUTFChars(locale, NULL);
+    Locale result = Locale::createFromName(name);
+    env->ReleaseStringUTFChars(locale, name);
+    return result;
+}
+
+static jstring getJStringFromUnicodeString(JNIEnv *env, UnicodeString string) {
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    int stringLength = string.length();
+    jchar *res = (jchar *) malloc(sizeof(jchar) * (stringLength + 1));
+    string.extract(res, stringLength+1, status);
+    if(U_FAILURE(status)) {
+        free(res);
+        LOGI("Error getting string for getJStringFromUnicodeString");
+        status = U_ZERO_ERROR;
+        return NULL;
+    }
+    jstring result = env->NewString(res, stringLength);
+    free(res);
+    return result;
+}
+
+static void addObject(JNIEnv *env, jobjectArray result, const char *keyStr, jobject elem, int index) {
+    jclass objArray_class = env->FindClass("java/lang/Object");
+    jobjectArray element = env->NewObjectArray(2, objArray_class, NULL);
+    jstring key = env->NewStringUTF(keyStr);
+    env->SetObjectArrayElement(element, 0, key);
+    env->SetObjectArrayElement(element, 1, elem);
+    env->SetObjectArrayElement(result, index, element);
+    env->DeleteLocalRef(key);
+    env->DeleteLocalRef(element);
+} 
+
+static jint getFractionDigitsNative(JNIEnv* env, jclass clazz, 
+        jstring currencyCode) {
+    // LOGI("ENTER getFractionDigitsNative");
+    
+    UErrorCode status = U_ZERO_ERROR;
+    
+    NumberFormat *fmt = NumberFormat::createCurrencyInstance(status);
+    if(U_FAILURE(status)) {
+        return -1;
+    }
+
+    const jchar *cCode = env->GetStringChars(currencyCode, NULL);
+    fmt->setCurrency(cCode, status);
+    env->ReleaseStringChars(currencyCode, cCode);
+    if(U_FAILURE(status)) {
+        return -1;
+    }
+    
+    // for CurrencyFormats the minimum and maximum fraction digits are the same.
+    int result = fmt->getMinimumFractionDigits(); 
+    delete(fmt);
+    return result;
+}
+
+static jstring getCurrencyCodeNative(JNIEnv* env, jclass clazz, 
+        jstring key) {
+    // LOGI("ENTER getCurrencyCodeNative");
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    UResourceBundle *supplData = ures_openDirect(NULL, "supplementalData", &status);
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+    UResourceBundle *currencyMap = ures_getByKey(supplData, "CurrencyMap", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(supplData);
+        return NULL;
+    }
+
+    const char *keyChars = env->GetStringUTFChars(key, NULL);
+    UResourceBundle *currency = ures_getByKey(currencyMap, keyChars, NULL, &status);
+    env->ReleaseStringUTFChars(key, keyChars);
+    if(U_FAILURE(status)) {
+        ures_close(currencyMap);
+        ures_close(supplData);
+        return NULL;
+    }
+
+    UResourceBundle *currencyElem = ures_getByIndex(currency, 0, NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(currency);
+        ures_close(currencyMap);
+        ures_close(supplData);
+        return NULL;
+    }
+
+    UResourceBundle *currencyId = ures_getByKey(currencyElem, "id", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(currencyElem);
+        ures_close(currency);
+        ures_close(currencyMap);
+        ures_close(supplData);
+        return NULL;
+    }
+
+    int length;
+    const jchar *id = ures_getString(currencyId, &length, &status);
+    if(U_FAILURE(status)) {
+        ures_close(currencyId);
+        ures_close(currencyElem);
+        ures_close(currency);
+        ures_close(currencyMap);
+        ures_close(supplData);
+        return NULL;
+    }
+
+    ures_close(currencyId);
+    ures_close(currencyElem);
+    ures_close(currency);
+    ures_close(currencyMap);
+    ures_close(supplData);
+
+    if(length == 0) {
+        return NULL;
+    }
+    return env->NewString(id, length);
+}
+
+static jstring getCurrencySymbolNative(JNIEnv* env, jclass clazz, 
+        jstring locale, jstring currencyCode) {
+    // LOGI("ENTER getCurrencySymbolNative");
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    const char *locName = env->GetStringUTFChars(locale, NULL);
+    UResourceBundle *root = ures_open(NULL, locName, &status);
+    env->ReleaseStringUTFChars(locale, locName);
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+    UResourceBundle *rootElems = ures_getByKey(root, "Currencies", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(root);
+        return NULL;
+    }
+
+    const char *currName = env->GetStringUTFChars(currencyCode, NULL);
+    UResourceBundle *currencyElems = ures_getByKey(rootElems, currName, NULL, &status);
+    env->ReleaseStringUTFChars(currencyCode, currName);
+    if(U_FAILURE(status)) {
+        ures_close(rootElems);
+        ures_close(root);
+        return NULL;
+    }
+
+    int currSymbL;
+    const jchar *currSymbU = ures_getStringByIndex(currencyElems, 0, &currSymbL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(currencyElems);
+        ures_close(rootElems);
+        ures_close(root);
+        return NULL;
+    }
+
+    ures_close(currencyElems);
+    ures_close(rootElems);
+    ures_close(root);
+
+    if(currSymbL == 0) {
+        return NULL;
+    }
+    return env->NewString(currSymbU, currSymbL);
+}
+
+static jstring getDisplayCountryNative(JNIEnv* env, jclass clazz, 
+        jstring targetLocale, jstring locale) {
+    // LOGI("ENTER getDisplayCountryNative");
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    Locale loc = getLocale(env, locale);
+    Locale targetLoc = getLocale(env, targetLocale);
+    
+    UnicodeString string;
+    targetLoc.getDisplayCountry(loc, string);
+
+    jstring result = getJStringFromUnicodeString(env, string);
+
+    return result;
+}
+
+static jstring getDisplayLanguageNative(JNIEnv* env, jclass clazz, 
+        jstring targetLocale, jstring locale) {
+    // LOGI("ENTER getDisplayLanguageNative");
+
+    Locale loc = getLocale(env, locale);
+    Locale targetLoc = getLocale(env, targetLocale);
+
+    UnicodeString string;
+    targetLoc.getDisplayLanguage(loc, string);
+    
+    jstring result = getJStringFromUnicodeString(env, string);
+    
+    return result;
+}
+
+static jstring getDisplayVariantNative(JNIEnv* env, jclass clazz, 
+        jstring targetLocale, jstring locale) {
+    // LOGI("ENTER getDisplayVariantNative");
+
+    Locale loc = getLocale(env, locale);
+    Locale targetLoc = getLocale(env, targetLocale);
+    
+    UnicodeString string;
+    targetLoc.getDisplayVariant(loc, string);
+    
+    jstring result = getJStringFromUnicodeString(env, string);
+    
+    return result;
+}
+
+static jstring getISO3CountryNative(JNIEnv* env, jclass clazz, jstring locale) {
+    // LOGI("ENTER getISO3CountryNative");
+
+    Locale loc = getLocale(env, locale);
+    
+    const char *string = loc.getISO3Country();
+    
+    jstring result = env->NewStringUTF(string);
+    
+    return result;
+}
+
+static jstring getISO3LanguageNative(JNIEnv* env, jclass clazz, jstring locale) {
+    // LOGI("ENTER getISO3LanguageNative");
+
+    Locale loc = getLocale(env, locale);
+    
+    const char *string = loc.getISO3Language();
+    
+    jstring result = env->NewStringUTF(string);
+    
+    return result;
+}
+
+static jobjectArray getISOCountriesNative(JNIEnv* env, jclass clazz) {
+    // LOGI("ENTER getISOCountriesNative");
+
+    const char* const* strings = Locale::getISOCountries();
+    
+    int count = 0;
+    while(strings[count] != NULL) {
+        count++;
+    }
+  
+    jobjectArray result = env->NewObjectArray(count, string_class, NULL);
+
+    jstring res;
+    for(int i = 0; i < count; i++) {
+        res = env->NewStringUTF(strings[i]);
+        env->SetObjectArrayElement(result, i, res);
+        env->DeleteLocalRef(res);
+    }
+    return result;
+}
+
+static jobjectArray getISOLanguagesNative(JNIEnv* env, jclass clazz) {
+    // LOGI("ENTER getISOLanguagesNative");
+    
+    const char* const* strings = Locale::getISOLanguages();
+    
+    const char *string = strings[0];
+    
+    int count = 0;
+    while(strings[count] != NULL) {
+        count++;
+    }
+    
+    jobjectArray result = env->NewObjectArray(count, string_class, NULL);
+
+    jstring res;
+    for(int i = 0; i < count; i++) {
+        res = env->NewStringUTF(strings[i]);
+        env->SetObjectArrayElement(result, i, res);
+        env->DeleteLocalRef(res);
+    }
+    return result;
+}
+
+static jobjectArray getAvailableLocalesNative(JNIEnv* env, jclass clazz) {
+    // LOGI("ENTER getAvailableLocalesNative");
+    
+    int count = uloc_countAvailable();
+    
+    jobjectArray result = env->NewObjectArray(count, string_class, NULL);
+
+    jstring res;
+    const char * string;    
+    for(int i = 0; i < count; i++) {
+        string = uloc_getAvailable(i);
+        res = env->NewStringUTF(string);
+        env->SetObjectArrayElement(result, i, res);
+        env->DeleteLocalRef(res);
+    }
+
+    return result;
+}
+
+static void getTimeZonesNative(JNIEnv* env, jclass clazz,
+        jobjectArray outerArray, jstring locale) {
+    // LOGI("ENTER getTimeZonesNative");
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    jobjectArray zoneIdArray;
+    jobjectArray longStdTimeArray;
+    jobjectArray shortStdTimeArray;
+    jobjectArray longDlTimeArray;
+    jobjectArray shortDlTimeArray;
+
+    jstring content;
+    jstring strObj;
+    const jchar *res;
+    UnicodeString resU;
+    jint length;
+    const UnicodeString *zoneID;
+    DateFormat *df;
+
+    UnicodeString longPattern("zzzz","");
+    UnicodeString shortPattern("z","");
+      
+    Locale loc = getLocale(env, locale);
+
+    SimpleDateFormat longFormat(longPattern, loc, status);
+    SimpleDateFormat shortFormat(shortPattern, loc, status);
+
+
+    zoneIdArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 0);
+    longStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 1);
+    shortStdTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 2);
+    longDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 3);
+    shortDlTimeArray = (jobjectArray) env->GetObjectArrayElement(outerArray, 4);
+
+    int count = env->GetArrayLength(zoneIdArray);
+
+    TimeZone* zones[count];
+    
+    // get all timezone objects
+    for(int i = 0; i < count; i++) {
+        strObj = (jstring) env->GetObjectArrayElement(zoneIdArray, i);
+        length = env->GetStringLength(strObj);
+        res = env->GetStringChars(strObj, NULL);
+        const UnicodeString zoneID((UChar *)res, length);
+        env->ReleaseStringChars(strObj, res);
+        zones[i] = TimeZone::createTimeZone(zoneID);
+    }
+
+    // 15th January 2008
+    UDate date1 = 1203105600000.0;
+    // 15th July 2008
+    UDate date2 = 1218826800000.0;
+
+    for (int i = 0; i < count; i++) {
+           TimeZone *tz = zones[i];
+           longFormat.setTimeZone(*tz);
+           shortFormat.setTimeZone(*tz);
+           
+           int32_t daylightOffset;
+           int32_t rawOffset;
+           UDate standardDate;
+           UDate daylightSavingDate;
+           tz->getOffset(date1, false, rawOffset, daylightOffset, status);
+           if (daylightOffset != 0) {
+               // The Timezone is reporting that we are in daylight time
+               // for the winter date.  The dates are for the wrong hemisphere,
+               // swap them.
+               standardDate = date2;
+               daylightSavingDate = date1;
+           } else {
+               standardDate = date1;
+               daylightSavingDate = date2;
+           }
+                     
+           UnicodeString shortDayLight;
+           UnicodeString longDayLight;
+           UnicodeString shortStandard;
+           UnicodeString longStandard;
+           
+           shortFormat.format(daylightSavingDate, shortDayLight);
+           content = getJStringFromUnicodeString(env, shortDayLight);
+           env->SetObjectArrayElement(shortDlTimeArray, i, content);
+           env->DeleteLocalRef(content);
+
+           shortFormat.format(standardDate, shortStandard);
+           content = getJStringFromUnicodeString(env, shortStandard);
+           env->SetObjectArrayElement(shortStdTimeArray, i, content);
+           env->DeleteLocalRef(content);
+
+           longFormat.format (daylightSavingDate, longDayLight);
+           content = getJStringFromUnicodeString(env, longDayLight);
+           env->SetObjectArrayElement(longDlTimeArray, i, content);
+           env->DeleteLocalRef(content);
+
+           longFormat.format (standardDate, longStandard);
+           content = getJStringFromUnicodeString(env, longStandard);
+           env->SetObjectArrayElement(longStdTimeArray, i, content);
+           env->DeleteLocalRef(content);
+           delete(tz);
+    }
+}
+
+
+
+
+static jstring getDisplayTimeZoneNative(JNIEnv* env, jclass clazz,
+        jstring zoneID, jboolean isDST, jint style, jstring localeID) {
+
+    // Build TimeZone object
+    const jchar* idChars = env->GetStringChars(zoneID, NULL);
+    jint idLength = env->GetStringLength(zoneID);
+    UnicodeString idString((UChar*)idChars, idLength);
+    TimeZone* zone = TimeZone::createTimeZone(idString);
+    env->ReleaseStringChars(zoneID, idChars);
+
+    // Build Locale object (can we rely on zero termination of JNI result?)
+    const char* localeChars = env->GetStringUTFChars(localeID, NULL);
+    jint localeLength = env->GetStringLength(localeID);
+    Locale locale = Locale::createFromName(localeChars);
+
+    // Try to get the display name of the TimeZone according to the Locale
+    UnicodeString buffer;
+    zone->getDisplayName((UBool)isDST, (style == 0 ? TimeZone::SHORT : TimeZone::LONG), locale, buffer);
+    const UChar* tempChars = buffer.getBuffer();
+    int tempLength = buffer.length();
+    jstring result = env->NewString((jchar*)tempChars, tempLength);
+    env->ReleaseStringUTFChars(localeID, localeChars);
+
+    // Clean up everything
+    delete(zone);
+    
+    return result;
+}
+
+static void getDayInitVector(JNIEnv *env, UResourceBundle *gregorian, int *values) {
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    // get the First day of week and the minimal days in first week numbers
+    UResourceBundle *gregorianElems = ures_getByKey(gregorian, "DateTimeElements", NULL, &status);
+    if(U_FAILURE(status)) {
+        return;
+    }
+
+    int intVectSize;
+    const int *result;
+    result = ures_getIntVector(gregorianElems, &intVectSize, &status);
+    if(U_FAILURE(status)) {
+        ures_close(gregorianElems);
+        return;
+    }
+
+    if(intVectSize == 2) {
+        values[0] = result[0];
+        values[1] = result[1];
+    }
+
+    ures_close(gregorianElems);
+
+}
+
+static jobjectArray getAmPmMarkers(JNIEnv *env, UResourceBundle *gregorian) {
+    
+    jobjectArray amPmMarkers;
+    jstring pmU, amU;
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    UResourceBundle *gregorianElems;
+
+    gregorianElems = ures_getByKey(gregorian, "AmPmMarkers", NULL, &status);
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+    int lengthAm, lengthPm;
+
+    ures_resetIterator(gregorianElems);
+
+    const jchar* am = ures_getStringByIndex(gregorianElems, 0, &lengthAm, &status);
+    const jchar* pm = ures_getStringByIndex(gregorianElems, 1, &lengthPm, &status);
+
+    if(U_FAILURE(status)) {
+        ures_close(gregorianElems);
+        return NULL;
+    }
+    
+    amPmMarkers = env->NewObjectArray(2, string_class, NULL);
+    amU = env->NewString(am, lengthAm);
+    env->SetObjectArrayElement(amPmMarkers, 0, amU);
+    env->DeleteLocalRef(amU);
+    pmU = env->NewString(pm, lengthPm);
+    env->SetObjectArrayElement(amPmMarkers, 1, pmU);
+    env->DeleteLocalRef(pmU);
+    ures_close(gregorianElems);
+
+    return amPmMarkers;
+}
+
+static jobjectArray getEras(JNIEnv* env, UResourceBundle *gregorian) {
+    
+    jobjectArray eras;
+    jstring eraU;
+    const jchar* era;
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    UResourceBundle *gregorianElems;
+    UResourceBundle *eraElems;
+
+    gregorianElems = ures_getByKey(gregorian, "eras", NULL, &status);
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+    eraElems = ures_getByKey(gregorianElems, "abbreviated", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(gregorianElems);
+        return NULL;
+    }
+
+    int eraLength;
+
+    int eraCount = ures_getSize(eraElems);
+    eras = env->NewObjectArray(eraCount, string_class, NULL);
+
+    ures_resetIterator(eraElems);
+    for(int i = 0; i < eraCount; i++) {
+        era = ures_getStringByIndex(eraElems, i, &eraLength, &status);
+        if(U_FAILURE(status)) {
+            ures_close(gregorianElems);
+            ures_close(eraElems);
+            return NULL;
+        }
+        eraU = env->NewString(era, eraLength);
+        env->SetObjectArrayElement(eras, i, eraU);
+        env->DeleteLocalRef(eraU);
+    }
+    ures_close(eraElems);
+    ures_close(gregorianElems);
+
+    return eras;
+}
+
+static jobjectArray getMonthNames(JNIEnv *env, UResourceBundle *gregorian) {
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    const jchar* month;
+    jstring monthU;
+
+    UResourceBundle *gregorianElems = ures_getByKey(gregorian, "monthNames", NULL, &status);
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+    UResourceBundle *monthNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(gregorianElems);
+        return NULL;
+    }
+
+    UResourceBundle *monthNameElemsFormat = ures_getByKey(monthNameElems, "wide", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(monthNameElems);
+        ures_close(gregorianElems);
+        return NULL;
+    }
+
+    int monthNameLength;
+    ures_resetIterator(monthNameElemsFormat);
+    int monthCount = ures_getSize(monthNameElemsFormat);
+    jobjectArray months = env->NewObjectArray(monthCount + 1, string_class, NULL);
+    for(int i = 0; i < monthCount; i++) {
+        month = ures_getStringByIndex(monthNameElemsFormat, i, &monthNameLength, &status);
+        if(U_FAILURE(status)) {
+            ures_close(monthNameElemsFormat);
+            ures_close(monthNameElems);
+            ures_close(gregorianElems);
+            return NULL;
+        }
+        monthU = env->NewString(month, monthNameLength);
+        env->SetObjectArrayElement(months, i, monthU);
+        env->DeleteLocalRef(monthU);
+    }
+
+    monthU = env->NewStringUTF("");
+    env->SetObjectArrayElement(months, monthCount, monthU);
+    env->DeleteLocalRef(monthU);
+
+    ures_close(monthNameElemsFormat);
+    ures_close(monthNameElems);
+    ures_close(gregorianElems);
+    return months;
+}
+
+static jobjectArray getShortMonthNames(JNIEnv *env, UResourceBundle *gregorian) {
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    const jchar* shortMonth;
+    jstring shortMonthU;
+
+    UResourceBundle *gregorianElems = ures_getByKey(gregorian, "monthNames", NULL, &status);
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+    UResourceBundle *monthNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(gregorianElems);
+        return NULL;
+    }
+
+    UResourceBundle *monthNameElemsFormat = ures_getByKey(monthNameElems, "abbreviated", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(monthNameElems);
+        ures_close(gregorianElems);
+        return NULL;
+    }
+
+    int shortMonthNameLength;
+    ures_resetIterator(monthNameElemsFormat);
+    int shortMonthCount = ures_getSize(monthNameElemsFormat);
+    // the array length is +1 because the harmony locales had an empty string at the end of their month name array
+    jobjectArray shortMonths = env->NewObjectArray(shortMonthCount + 1, string_class, NULL);
+    for(int i = 0; i < shortMonthCount; i++) {
+        shortMonth = ures_getStringByIndex(monthNameElemsFormat, i, &shortMonthNameLength, &status);
+        if(U_FAILURE(status)) {
+            ures_close(monthNameElemsFormat);
+            ures_close(monthNameElems);
+            ures_close(gregorianElems);
+            return NULL;
+        }
+        shortMonthU = env->NewString(shortMonth, shortMonthNameLength);
+        env->SetObjectArrayElement(shortMonths, i, shortMonthU);
+        env->DeleteLocalRef(shortMonthU);
+    }
+
+    shortMonthU = env->NewStringUTF("");
+    env->SetObjectArrayElement(shortMonths, shortMonthCount, shortMonthU);
+    env->DeleteLocalRef(shortMonthU);
+
+    ures_close(monthNameElemsFormat);
+    ures_close(monthNameElems);
+    ures_close(gregorianElems);
+    return shortMonths;
+}
+
+static jobjectArray getWeekdayNames(JNIEnv *env, UResourceBundle *gregorian) {
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    const jchar* day;
+    jstring dayU;
+
+    UResourceBundle *gregorianElems = ures_getByKey(gregorian, "dayNames", NULL, &status);
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+    UResourceBundle *dayNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(gregorianElems);
+        return NULL;
+    }
+
+    UResourceBundle *dayNameElemsFormat = ures_getByKey(dayNameElems, "wide", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(dayNameElems);
+        ures_close(gregorianElems);
+        return NULL;
+    }
+
+    int dayNameLength;
+    ures_resetIterator(dayNameElemsFormat);
+    int dayCount = ures_getSize(dayNameElemsFormat);
+    jobjectArray weekdays = env->NewObjectArray(dayCount + 1, string_class, NULL);
+    // first entry in the weekdays array is an empty string
+    env->SetObjectArrayElement(weekdays, 0, env->NewStringUTF(""));
+    for(int i = 0; i < dayCount; i++) {
+        day = ures_getStringByIndex(dayNameElemsFormat, i, &dayNameLength, &status);
+        if(U_FAILURE(status)) {
+            ures_close(dayNameElemsFormat);
+            ures_close(dayNameElems);
+            ures_close(gregorianElems);
+            return NULL;
+        }
+        dayU = env->NewString(day, dayNameLength);
+        env->SetObjectArrayElement(weekdays, i + 1, dayU);
+        env->DeleteLocalRef(dayU);
+    }
+    
+    ures_close(dayNameElemsFormat);
+    ures_close(dayNameElems);
+    ures_close(gregorianElems);
+    return weekdays;
+
+}
+
+static jobjectArray getShortWeekdayNames(JNIEnv *env, UResourceBundle *gregorian) {
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    const jchar* shortDay;
+    jstring shortDayU;
+
+    UResourceBundle *gregorianElems = ures_getByKey(gregorian, "dayNames", NULL, &status);
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+    UResourceBundle *dayNameElems = ures_getByKey(gregorianElems, "format", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(gregorianElems);
+        return NULL;
+    }
+
+    UResourceBundle *dayNameElemsFormat = ures_getByKey(dayNameElems, "abbreviated", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(dayNameElems);
+        ures_close(gregorianElems);
+        return NULL;
+    }
+
+    int shortDayNameLength;
+    ures_resetIterator(dayNameElemsFormat);
+    int shortDayCount = ures_getSize(dayNameElemsFormat);
+    jobjectArray shortWeekdays = env->NewObjectArray(shortDayCount + 1, string_class, NULL);
+    env->SetObjectArrayElement(shortWeekdays, 0, env->NewStringUTF(""));
+    for(int i = 0; i < shortDayCount; i++) {
+        shortDay = ures_getStringByIndex(dayNameElemsFormat, i, &shortDayNameLength, &status);
+        if(U_FAILURE(status)) {
+            ures_close(dayNameElemsFormat);
+            ures_close(dayNameElems);
+            ures_close(gregorianElems);
+            return NULL;
+        }
+        shortDayU = env->NewString(shortDay, shortDayNameLength);
+        env->SetObjectArrayElement(shortWeekdays, i + 1, shortDayU);
+        env->DeleteLocalRef(shortDayU);
+    }
+
+    ures_close(dayNameElemsFormat);
+    ures_close(dayNameElems);
+    ures_close(gregorianElems);
+    return shortWeekdays;
+}
+
+static jstring getDecimalPatternChars(JNIEnv *env, UResourceBundle *rootElems) {
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    int zeroL, digitL, decSepL, groupL, listL, percentL, permillL, expL, currSepL, minusL;
+    int patternLength;
+
+    jchar *patternChars;
+
+    const jchar* zero = ures_getStringByIndex(rootElems, 4, &zeroL, &status);
+
+    const jchar* digit = ures_getStringByIndex(rootElems, 5, &digitL, &status);
+
+    const jchar* decSep = ures_getStringByIndex(rootElems, 0, &decSepL, &status);
+
+    const jchar* group = ures_getStringByIndex(rootElems, 1, &groupL, &status);
+
+    const jchar* list = ures_getStringByIndex(rootElems, 2, &listL, &status);
+
+    const jchar* percent = ures_getStringByIndex(rootElems, 3, &percentL, &status);
+
+    const jchar* permill = ures_getStringByIndex(rootElems, 8, &permillL, &status);
+
+    const jchar* exp = ures_getStringByIndex(rootElems, 7, &expL, &status);
+
+    const jchar* currSep = ures_getStringByIndex(rootElems, 0, &currSepL, &status);
+
+    const jchar* minus = ures_getStringByIndex(rootElems, 6, &minusL, &status);
+
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+
+    patternChars = (jchar *) malloc(11 * sizeof(jchar));
+
+    patternChars[0] = 0;
+
+    u_strncat(patternChars, zero, 1);
+    u_strncat(patternChars, digit, 1);
+    u_strncat(patternChars, decSep, 1);
+    u_strncat(patternChars, group, 1);
+    u_strncat(patternChars, list, 1);
+    u_strncat(patternChars, percent, 1);
+    u_strncat(patternChars, permill, 1);
+    u_strncat(patternChars, exp, 1);
+    u_strncat(patternChars, currSep, 1);
+    u_strncat(patternChars, minus, 1);
+
+    jstring decimalPatternChars = env->NewString(patternChars, 10);
+
+    free(patternChars);
+
+    return decimalPatternChars;
+}
+
+static jstring getIntCurrencyCode(JNIEnv *env, jclass clazz, jstring locale) {
+
+    const char *locStr = env->GetStringUTFChars(locale, NULL);
+    char country[3] = {0,0,0};
+
+    // getting the 2 character country name
+    if(strlen(locStr) < 5) {
+        env->ReleaseStringUTFChars(locale, locStr);
+        return NULL;
+    }
+    if(locStr[3] < 'A' || locStr[3] > 'Z' || locStr[4] < 'A' || locStr[4] > 'Z') {
+        env->ReleaseStringUTFChars(locale, locStr);
+        return NULL;
+    }
+    country[0] = locStr[3];
+    country[1] = locStr[4];
+
+    env->ReleaseStringUTFChars(locale, locStr);
+
+    return getCurrencyCodeNative(env, clazz, env->NewStringUTF(country));
+}
+
+static jstring getCurrencySymbol(JNIEnv *env, jclass clazz, jstring locale, jstring intCurrencySymbol) {
+
+    jstring result = getCurrencySymbolNative(env, clazz, locale, intCurrencySymbol);
+    if(result == intCurrencySymbol) {
+        return NULL;
+    }
+    return result;
+
+}
+
+static jobjectArray getContentImpl(JNIEnv* env, jclass clazz, 
+        jstring locale, jboolean needsTZ) {
+    
+    UErrorCode status = U_ZERO_ERROR;
+
+    const char *loc = env->GetStringUTFChars(locale, NULL);
+    UResourceBundle *root = ures_openU(NULL, loc, &status);
+
+    env->ReleaseStringUTFChars(locale, loc);
+    if(U_FAILURE(status)) {
+        LOGI("Error getting resources");
+        status = U_ZERO_ERROR;
+        return NULL;
+    }
+
+
+
+    jclass obj_class = env->FindClass("java/lang/Object");
+    jclass integer_class = env->FindClass("java/lang/Integer");
+    jmethodID integerInit = env->GetMethodID(integer_class, "<init>", "(I)V");
+    jobjectArray result;
+
+    jobject firstDayOfWeek = NULL;
+    jobject minimalDaysInFirstWeek = NULL;
+    jobjectArray amPmMarkers = NULL;
+    jobjectArray eras = NULL;
+    jstring localPatternChars = NULL;
+    jobjectArray weekdays = NULL;
+    jobjectArray shortWeekdays = NULL;
+    jobjectArray months = NULL;
+    jobjectArray shortMonths = NULL;
+    jstring time_SHORT = NULL;
+    jstring time_MEDIUM = NULL;
+    jstring time_LONG = NULL;
+    jstring time_FULL = NULL;
+    jstring date_SHORT = NULL;
+    jstring date_MEDIUM = NULL;
+    jstring date_LONG = NULL;
+    jstring date_FULL = NULL;
+    jstring decimalPatternChars = NULL;
+    jstring naN = NULL;
+    jstring infinity = NULL;
+    jstring currencySymbol = NULL;
+    jstring intCurrencySymbol = NULL;
+    jstring numberPattern = NULL;
+    jstring integerPattern = NULL;
+    jstring currencyPattern = NULL;
+    jstring percentPattern = NULL;
+    jobjectArray zones = NULL;
+
+    int counter = 0;
+
+    int firstDayVals[2] = {-1, -1};
+
+    const jchar* nan = (const jchar *)NULL;
+    const jchar* inf = (const jchar *)NULL;
+    int nanL, infL;
+
+
+    UResourceBundle *gregorian;
+    UResourceBundle *gregorianElems;
+    UResourceBundle *rootElems;
+
+
+
+
+    // get the resources needed
+    rootElems = ures_getByKey(root, "calendar", NULL, &status);
+    if(U_FAILURE(status)) {
+        return NULL;
+    }
+
+    gregorian = ures_getByKey(rootElems, "gregorian", NULL, &status);
+    if(U_FAILURE(status)) {
+        ures_close(rootElems);
+        return NULL;
+    }
+
+
+
+    // adding the first day of week and minimal days in first week values
+    getDayInitVector(env, gregorian, firstDayVals);
+    if((firstDayVals[0] != -1) && (firstDayVals[1] != -1)) {
+        firstDayOfWeek = env->NewObject(integer_class, integerInit, firstDayVals[0]);
+        minimalDaysInFirstWeek = env->NewObject(integer_class, integerInit, firstDayVals[1]);
+        // adding First_Day and Minimal_Days integer to the result
+        counter += 2;
+    }
+
+
+    // adding ampm string array to the result");
+    amPmMarkers = getAmPmMarkers(env, gregorian);
+    if(amPmMarkers != NULL) {
+        counter++;
+    }
+
+
+    // adding eras string array to the result
+    eras = getEras(env, gregorian);
+    if(eras != NULL) {
+        counter++;
+    }
+
+
+    // local pattern chars are initially always the same
+    localPatternChars = env->NewStringUTF("GyMdkHmsSEDFwWahKzZ");
+    // adding local pattern chars string to the result
+    counter++;
+
+
+    // adding month names string array to the result
+    months = getMonthNames(env, gregorian);
+    if(months != NULL) {
+        counter++;
+    }
+
+
+    // adding short month names string array to the result
+    shortMonths = getShortMonthNames(env, gregorian);
+    if(shortMonths != NULL) {
+        counter++;
+    }
+
+
+    // adding day names string array to the result
+    weekdays = getWeekdayNames(env, gregorian);
+    if(weekdays != NULL) {
+        counter++;
+    }
+
+
+    // adding short day names string array to the result
+    shortWeekdays = getShortWeekdayNames(env, gregorian);
+    if(shortWeekdays != NULL) {
+        counter++;
+    }
+
+    const UChar *pattern;
+    jchar check[2] = {0, 0};
+    u_uastrcpy(check, "v");
+    jchar replacement[2] = {0, 0};
+    u_uastrcpy(replacement, "z");
+    jchar *pos;
+    jchar *patternCopy;
+    int patternLength;
+
+    // adding date and time format patterns to the result
+    gregorianElems = ures_getByKey(gregorian, "DateTimePatterns", NULL, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        goto endOfCalendar;
+    }
+
+    pattern = ures_getStringByIndex(gregorianElems, 0, &patternLength, &status);
+    // there are some patterns in icu that use the pattern character 'v'
+    // java doesn't accept this, so it gets replaced by 'z' which has
+    // about the same result as 'v', the timezone name. 
+    // 'v' -> "PT", 'z' -> "PST", v is the generic timezone and z the standard tz
+    // "vvvv" -> "Pacific Time", "zzzz" -> "Pacific Standard Time"
+    patternCopy = (jchar *) malloc((patternLength + 1) * sizeof(jchar));
+    u_strcpy(patternCopy, pattern);
+    if(U_FAILURE(status)) {
+        free(patternCopy);
+        status = U_ZERO_ERROR;
+        goto endOfCalendar;
+    }
+    while((pos = u_strchr(patternCopy, check[0])) != NULL) {
+        u_memset(pos, replacement[0], 1);
+    }
+    time_FULL = env->NewString(patternCopy, patternLength);
+    free(patternCopy);
+    counter++;
+
+    pattern = ures_getStringByIndex(gregorianElems, 1, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        goto endOfCalendar;
+    }
+    time_LONG = env->NewString(pattern, patternLength);
+    counter++;
+
+    pattern = ures_getStringByIndex(gregorianElems, 2, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        goto endOfCalendar;
+    }
+    time_MEDIUM = env->NewString(pattern, patternLength);
+    counter++;
+
+    pattern = ures_getStringByIndex(gregorianElems, 3, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        goto endOfCalendar;
+    }
+    time_SHORT = env->NewString(pattern, patternLength);
+    counter++;
+
+    pattern = ures_getStringByIndex(gregorianElems, 4, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        goto endOfCalendar;
+    }
+    date_FULL = env->NewString(pattern, patternLength);
+    counter++;
+
+    pattern = ures_getStringByIndex(gregorianElems, 5, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        goto endOfCalendar;
+    }
+    date_LONG = env->NewString(pattern, patternLength);
+    counter++;
+
+    pattern = ures_getStringByIndex(gregorianElems, 6, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        goto endOfCalendar;
+    }
+    date_MEDIUM = env->NewString(pattern, patternLength);
+    counter++;
+
+    pattern = ures_getStringByIndex(gregorianElems, 7, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        goto endOfCalendar;
+    }
+    date_SHORT = env->NewString(pattern, patternLength);
+    counter++;
+
+
+endOfCalendar:
+
+    if(gregorianElems != NULL) {
+        ures_close(gregorianElems);
+    }
+    ures_close(gregorian);
+    ures_close(rootElems);
+
+
+    rootElems = ures_getByKey(root, "NumberElements", NULL, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+    }
+
+    if(ures_getSize(rootElems) >= 11) {
+
+        // adding decimal pattern chars to the result
+        decimalPatternChars = getDecimalPatternChars(env, rootElems);
+        if(decimalPatternChars != NULL) {
+            counter++;
+        }
+
+        // adding NaN pattern char to the result
+        nan = ures_getStringByIndex(rootElems, 10, &nanL, &status);
+        if(U_SUCCESS(status)) {
+            naN = env->NewString(nan, nanL);
+            counter++;
+        }
+        status = U_ZERO_ERROR;
+
+        // adding infinity pattern char to the result
+        inf = ures_getStringByIndex(rootElems, 9, &infL, &status);
+        if(U_SUCCESS(status)) {
+            infinity = env->NewString(inf, infL);
+            counter++;
+        }
+        status = U_ZERO_ERROR;
+    }
+
+    ures_close(rootElems);
+
+
+    // adding intl currency code to result
+    intCurrencySymbol = getIntCurrencyCode(env, clazz, locale);
+    if(intCurrencySymbol != NULL) {
+        // adding currency symbol to result
+        currencySymbol = getCurrencySymbol(env, clazz, locale, intCurrencySymbol);
+    } else {
+        intCurrencySymbol = env->NewStringUTF("XXX");
+    }
+    if(currencySymbol == NULL) {
+        currencySymbol = env->NewStringUTF("\u00a4");
+    }
+    counter += 2;
+
+
+    // adding number format patterns to the result
+    int numOfEntries;
+    int decSepOffset;
+    NumberFormat *nf;
+    jchar *tmpPattern;
+
+    rootElems = ures_getByKey(root, "NumberPatterns", NULL, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        goto zones;
+    }
+
+    numOfEntries = ures_getSize(rootElems);
+    if(numOfEntries < 3) {
+        ures_close(rootElems);
+        goto zones;
+    }
+
+    // number pattern
+    pattern = ures_getStringByIndex(rootElems, 0, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        ures_close(rootElems);
+        goto zones;
+    }
+    numberPattern = env->NewString(pattern, patternLength);
+    counter++;
+
+    // integer pattern derived from number pattern
+    decSepOffset = u_strcspn(pattern, (jchar *)".\0");
+    tmpPattern =  (jchar *) malloc((decSepOffset + 1) * sizeof(jchar));
+    u_strncpy(tmpPattern, pattern, decSepOffset);
+    integerPattern = env->NewString(tmpPattern, decSepOffset);
+    free(tmpPattern);
+    counter++;
+
+    // currency pattern
+    pattern = ures_getStringByIndex(rootElems, 1, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        ures_close(rootElems);
+        goto zones;
+    }
+    currencyPattern = env->NewString(pattern, patternLength);
+    counter++;
+
+    // percent pattern
+    pattern = ures_getStringByIndex(rootElems, 2, &patternLength, &status);
+    if(U_FAILURE(status)) {
+        status = U_ZERO_ERROR;
+        ures_close(rootElems);
+        goto zones;
+    }
+    percentPattern = env->NewString(pattern, patternLength);
+    counter++;
+
+    ures_close(rootElems);
+
+zones:
+
+    ures_close(root);
+
+
+    if(needsTZ == JNI_TRUE) {
+        counter++; //add empty timezone
+    }
+
+
+
+    // collect all content and put it into an array
+    result = env->NewObjectArray(counter, obj_class, NULL);
+
+    int index = 0;
+    
+    if(needsTZ == JNI_TRUE) {
+        addObject(env, result, "timezones", NULL, index++);
+    }
+    if(firstDayOfWeek != NULL && index < counter) {
+        addObject(env, result, "First_Day", firstDayOfWeek, index++);
+    }
+    if(minimalDaysInFirstWeek != NULL && index < counter) {
+        addObject(env, result, "Minimal_Days", minimalDaysInFirstWeek, index++);
+    }
+    if(amPmMarkers != NULL && index < counter) {
+        addObject(env, result, "ampm", amPmMarkers, index++);
+    }
+    if(eras != NULL && index < counter) {
+        addObject(env, result, "eras", eras, index++);
+    }
+    if(localPatternChars != NULL && index < counter) {
+        addObject(env, result, "LocalPatternChars", localPatternChars, index++);
+    }
+    if(weekdays != NULL && index < counter) {
+        addObject(env, result, "weekdays", weekdays, index++);
+    }
+    if(shortWeekdays != NULL && index < counter) {
+        addObject(env, result, "shortWeekdays", shortWeekdays, index++);
+    }
+    if(months != NULL && index < counter) {
+        addObject(env, result, "months", months, index++);
+    }
+    if(shortMonths != NULL && index < counter) {
+        addObject(env, result, "shortMonths", shortMonths, index++);
+    }
+    if(time_SHORT != NULL && index < counter) {
+        addObject(env, result, "Time_SHORT", time_SHORT, index++);
+    }
+    if(time_MEDIUM != NULL && index < counter) {
+        addObject(env, result, "Time_MEDIUM", time_MEDIUM, index++);
+    }
+    if(time_LONG != NULL && index < counter) {
+        addObject(env, result, "Time_LONG", time_LONG, index++);
+    }
+    if(time_FULL != NULL && index < counter) {
+        addObject(env, result, "Time_FULL", time_FULL, index++);
+    }
+    if(date_SHORT != NULL && index < counter) {
+        addObject(env, result, "Date_SHORT", date_SHORT, index++);
+    }
+    if(date_MEDIUM != NULL && index < counter) {
+        addObject(env, result, "Date_MEDIUM", date_MEDIUM, index++);
+    }
+    if(date_LONG != NULL && index < counter) {
+        addObject(env, result, "Date_LONG", date_LONG, index++);
+    }
+    if(date_FULL != NULL && index < counter) {
+        addObject(env, result, "Date_FULL", date_FULL, index++);
+    }
+    if(decimalPatternChars != NULL && index < counter) {
+        addObject(env, result, "DecimalPatternChars", decimalPatternChars, index++);
+    }
+    if(naN != NULL && index < counter) {
+        addObject(env, result, "NaN", naN, index++);
+    }
+    if(infinity != NULL && index < counter) {
+        addObject(env, result, "Infinity", infinity, index++);
+    }
+    if(currencySymbol != NULL && index < counter) {
+        addObject(env, result, "CurrencySymbol", currencySymbol, index++);
+    }
+    if(intCurrencySymbol != NULL && index < counter) {
+        addObject(env, result, "IntCurrencySymbol", intCurrencySymbol, index++);
+    }
+    if(numberPattern != NULL && index < counter) {
+        addObject(env, result, "Number", numberPattern, index++);
+    }
+    if(integerPattern != NULL && index < counter) {
+        addObject(env, result, "Integer", integerPattern, index++);
+    }
+    if(currencyPattern != NULL && index < counter) {
+        addObject(env, result, "Currency", currencyPattern, index++);
+    }
+    if(percentPattern != NULL && index < counter) {
+        addObject(env, result, "Percent", percentPattern, index++);
+    }
+
+    return result;
+
+}
+
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    {"getFractionDigitsNative", "(Ljava/lang/String;)I",                   
+            (void*) getFractionDigitsNative},
+    {"getCurrencyCodeNative", "(Ljava/lang/String;)Ljava/lang/String;",
+            (void*) getCurrencyCodeNative},
+    {"getCurrencySymbolNative", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+            (void*) getCurrencySymbolNative},
+    {"getDisplayCountryNative", 
+            "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+            (void*) getDisplayCountryNative},
+    {"getDisplayLanguageNative", 
+            "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+            (void*) getDisplayLanguageNative},
+    {"getDisplayVariantNative",
+            "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+            (void*) getDisplayVariantNative},
+    {"getISO3CountryNative",
+            "(Ljava/lang/String;)Ljava/lang/String;",
+            (void*) getISO3CountryNative},
+    {"getISO3LanguageNative",
+            "(Ljava/lang/String;)Ljava/lang/String;",
+            (void*) getISO3LanguageNative},
+    {"getISOCountriesNative", "()[Ljava/lang/String;",
+            (void*) getISOCountriesNative},
+    {"getISOLanguagesNative", "()[Ljava/lang/String;",
+            (void*) getISOLanguagesNative},
+    {"getAvailableLocalesNative", "()[Ljava/lang/String;",
+            (void*) getAvailableLocalesNative},
+    {"getTimeZonesNative", 
+            "([[Ljava/lang/String;Ljava/lang/String;)V",
+            (void*) getTimeZonesNative},
+    {"getDisplayTimeZoneNative", 
+            "(Ljava/lang/String;ZILjava/lang/String;)Ljava/lang/String;",
+            (void*) getDisplayTimeZoneNative},
+    {"getContentImpl", 
+            "(Ljava/lang/String;Z)[[Ljava/lang/Object;",
+            (void*) getContentImpl},
+};
+
+int register_com_ibm_icu4jni_util_Resources(JNIEnv* env) {
+    
+    // initializing String
+
+    jclass stringclass = env->FindClass("java/lang/String");
+
+    if(stringclass == NULL) {
+        LOGE("Can't find java/lang/String");
+        jniThrowException(env, "java/lang/ClassNotFoundException", "java.lang.String");
+        return -1;
+    }
+    
+    string_class = (jclass) env->NewGlobalRef(stringclass);
+    
+    return jniRegisterNativeMethods(env, 
+            "com/ibm/icu4jni/util/Resources", gMethods, 
+            NELEM(gMethods));
+}
diff --git a/libcore/icu/src/main/native/sub.mk b/libcore/icu/src/main/native/sub.mk
new file mode 100644
index 0000000..2f160f5
--- /dev/null
+++ b/libcore/icu/src/main/native/sub.mk
@@ -0,0 +1,30 @@
+# This file is included by the top-level libcore Android.mk.
+# It's not a normal makefile, so we don't include CLEAR_VARS
+# or BUILD_*_LIBRARY.
+
+LOCAL_SRC_FILES := \
+	BidiWrapperInterface.c \
+	BreakIteratorInterface.c \
+	DecimalFormatInterface.cpp \
+	CharacterInterface.c \
+	ConverterInterface.c \
+	CollationInterface.c \
+	RegExInterface.cpp \
+	ResourceInterface.cpp \
+	RBNFInterface.cpp \
+	ErrorCode.c
+
+LOCAL_C_INCLUDES += \
+	external/icu4c/common \
+	external/icu4c/i18n
+
+# Any shared/static libs that are listed here must also
+# be listed in libs/nativehelper/Android.mk.
+# TODO: fix this requirement
+
+LOCAL_SHARED_LIBRARIES += \
+	libicudata \
+	libicuuc \
+	libicui18n
+
+LOCAL_STATIC_LIBRARIES +=